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,
64 isTouch = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
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,
622 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
623 * you may want to set this to true.
626 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
631 * Selects a single element as a Roo Element
632 * This is about as close as you can get to jQuery's $('do crazy stuff')
633 * @param {String} selector The selector/xpath query
634 * @param {Node} root (optional) The start of the query (defaults to document).
635 * @return {Roo.Element}
637 selectNode : function(selector, root)
639 var node = Roo.DomQuery.selectNode(selector,root);
640 return node ? Roo.get(node) : new Roo.Element(false);
648 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
649 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
652 "Roo.boostrap.dash");
655 * Ext JS Library 1.1.1
656 * Copyright(c) 2006-2007, Ext JS, LLC.
658 * Originally Released Under LGPL - original licence link has changed is not relivant.
661 * <script type="text/javascript">
665 // wrappedn so fnCleanup is not in global scope...
667 function fnCleanUp() {
668 var p = Function.prototype;
669 delete p.createSequence;
671 delete p.createDelegate;
672 delete p.createCallback;
673 delete p.createInterceptor;
675 window.detachEvent("onunload", fnCleanUp);
677 window.attachEvent("onunload", fnCleanUp);
684 * These functions are available on every Function object (any JavaScript function).
686 Roo.apply(Function.prototype, {
688 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
689 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
690 * Will create a function that is bound to those 2 args.
691 * @return {Function} The new function
693 createCallback : function(/*args...*/){
694 // make args available, in function below
695 var args = arguments;
698 return method.apply(window, args);
703 * Creates a delegate (callback) that sets the scope to obj.
704 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
705 * Will create a function that is automatically scoped to this.
706 * @param {Object} obj (optional) The object for which the scope is set
707 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
708 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
709 * if a number the args are inserted at the specified position
710 * @return {Function} The new function
712 createDelegate : function(obj, args, appendArgs){
715 var callArgs = args || arguments;
716 if(appendArgs === true){
717 callArgs = Array.prototype.slice.call(arguments, 0);
718 callArgs = callArgs.concat(args);
719 }else if(typeof appendArgs == "number"){
720 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
721 var applyArgs = [appendArgs, 0].concat(args); // create method call params
722 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
724 return method.apply(obj || window, callArgs);
729 * Calls this function after the number of millseconds specified.
730 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
731 * @param {Object} obj (optional) The object for which the scope is set
732 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
733 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
734 * if a number the args are inserted at the specified position
735 * @return {Number} The timeout id that can be used with clearTimeout
737 defer : function(millis, obj, args, appendArgs){
738 var fn = this.createDelegate(obj, args, appendArgs);
740 return setTimeout(fn, millis);
746 * Create a combined function call sequence of the original function + the passed function.
747 * The resulting function returns the results of the original function.
748 * The passed fcn is called with the parameters of the original function
749 * @param {Function} fcn The function to sequence
750 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
751 * @return {Function} The new function
753 createSequence : function(fcn, scope){
754 if(typeof fcn != "function"){
759 var retval = method.apply(this || window, arguments);
760 fcn.apply(scope || this || window, arguments);
766 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
767 * The resulting function returns the results of the original function.
768 * The passed fcn is called with the parameters of the original function.
770 * @param {Function} fcn The function to call before the original
771 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
772 * @return {Function} The new function
774 createInterceptor : function(fcn, scope){
775 if(typeof fcn != "function"){
782 if(fcn.apply(scope || this || window, arguments) === false){
785 return method.apply(this || window, arguments);
791 * Ext JS Library 1.1.1
792 * Copyright(c) 2006-2007, Ext JS, LLC.
794 * Originally Released Under LGPL - original licence link has changed is not relivant.
797 * <script type="text/javascript">
800 Roo.applyIf(String, {
805 * Escapes the passed string for ' and \
806 * @param {String} string The string to escape
807 * @return {String} The escaped string
810 escape : function(string) {
811 return string.replace(/('|\\)/g, "\\$1");
815 * Pads the left side of a string with a specified character. This is especially useful
816 * for normalizing number and date strings. Example usage:
818 var s = String.leftPad('123', 5, '0');
819 // s now contains the string: '00123'
821 * @param {String} string The original string
822 * @param {Number} size The total length of the output string
823 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
824 * @return {String} The padded string
827 leftPad : function (val, size, ch) {
828 var result = new String(val);
829 if(ch === null || ch === undefined || ch === '') {
832 while (result.length < size) {
833 result = ch + result;
839 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
840 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
842 var cls = 'my-class', text = 'Some text';
843 var s = String.format('<div class="{0}">{1}</div>', cls, text);
844 // s now contains the string: '<div class="my-class">Some text</div>'
846 * @param {String} string The tokenized string to be formatted
847 * @param {String} value1 The value to replace token {0}
848 * @param {String} value2 Etc...
849 * @return {String} The formatted string
852 format : function(format){
853 var args = Array.prototype.slice.call(arguments, 1);
854 return format.replace(/\{(\d+)\}/g, function(m, i){
855 return Roo.util.Format.htmlEncode(args[i]);
861 * Utility function that allows you to easily switch a string between two alternating values. The passed value
862 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
863 * they are already different, the first value passed in is returned. Note that this method returns the new value
864 * but does not change the current string.
866 // alternate sort directions
867 sort = sort.toggle('ASC', 'DESC');
869 // instead of conditional logic:
870 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
872 * @param {String} value The value to compare to the current string
873 * @param {String} other The new value to use if the string already equals the first value passed in
874 * @return {String} The new value
877 String.prototype.toggle = function(value, other){
878 return this == value ? other : value;
881 * Ext JS Library 1.1.1
882 * Copyright(c) 2006-2007, Ext JS, LLC.
884 * Originally Released Under LGPL - original licence link has changed is not relivant.
887 * <script type="text/javascript">
893 Roo.applyIf(Number.prototype, {
895 * Checks whether or not the current number is within a desired range. If the number is already within the
896 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
897 * exceeded. Note that this method returns the constrained value but does not change the current number.
898 * @param {Number} min The minimum number in the range
899 * @param {Number} max The maximum number in the range
900 * @return {Number} The constrained value if outside the range, otherwise the current value
902 constrain : function(min, max){
903 return Math.min(Math.max(this, min), max);
907 * Ext JS Library 1.1.1
908 * Copyright(c) 2006-2007, Ext JS, LLC.
910 * Originally Released Under LGPL - original licence link has changed is not relivant.
913 * <script type="text/javascript">
918 Roo.applyIf(Array.prototype, {
920 * Checks whether or not the specified object exists in the array.
921 * @param {Object} o The object to check for
922 * @return {Number} The index of o in the array (or -1 if it is not found)
924 indexOf : function(o){
925 for (var i = 0, len = this.length; i < len; i++){
926 if(this[i] == o) return i;
932 * Removes the specified object from the array. If the object is not found nothing happens.
933 * @param {Object} o The object to remove
935 remove : function(o){
936 var index = this.indexOf(o);
938 this.splice(index, 1);
942 * Map (JS 1.6 compatibility)
943 * @param {Function} function to call
947 var len = this.length >>> 0;
948 if (typeof fun != "function")
949 throw new TypeError();
951 var res = new Array(len);
952 var thisp = arguments[1];
953 for (var i = 0; i < len; i++)
956 res[i] = fun.call(thisp, this[i], i, this);
967 * Ext JS Library 1.1.1
968 * Copyright(c) 2006-2007, Ext JS, LLC.
970 * Originally Released Under LGPL - original licence link has changed is not relivant.
973 * <script type="text/javascript">
979 * The date parsing and format syntax is a subset of
980 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
981 * supported will provide results equivalent to their PHP versions.
983 * Following is the list of all currently supported formats:
986 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
988 Format Output Description
989 ------ ---------- --------------------------------------------------------------
990 d 10 Day of the month, 2 digits with leading zeros
991 D Wed A textual representation of a day, three letters
992 j 10 Day of the month without leading zeros
993 l Wednesday A full textual representation of the day of the week
994 S th English ordinal day of month suffix, 2 chars (use with j)
995 w 3 Numeric representation of the day of the week
996 z 9 The julian date, or day of the year (0-365)
997 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
998 F January A full textual representation of the month
999 m 01 Numeric representation of a month, with leading zeros
1000 M Jan Month name abbreviation, three letters
1001 n 1 Numeric representation of a month, without leading zeros
1002 t 31 Number of days in the given month
1003 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1004 Y 2007 A full numeric representation of a year, 4 digits
1005 y 07 A two digit representation of a year
1006 a pm Lowercase Ante meridiem and Post meridiem
1007 A PM Uppercase Ante meridiem and Post meridiem
1008 g 3 12-hour format of an hour without leading zeros
1009 G 15 24-hour format of an hour without leading zeros
1010 h 03 12-hour format of an hour with leading zeros
1011 H 15 24-hour format of an hour with leading zeros
1012 i 05 Minutes with leading zeros
1013 s 01 Seconds, with leading zeros
1014 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1015 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1016 T CST Timezone setting of the machine running the code
1017 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1020 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1022 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1023 document.write(dt.format('Y-m-d')); //2007-01-10
1024 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1025 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
1028 * Here are some standard date/time patterns that you might find helpful. They
1029 * are not part of the source of Date.js, but to use them you can simply copy this
1030 * block of code into any script that is included after Date.js and they will also become
1031 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1034 ISO8601Long:"Y-m-d H:i:s",
1035 ISO8601Short:"Y-m-d",
1037 LongDate: "l, F d, Y",
1038 FullDateTime: "l, F d, Y g:i:s A",
1041 LongTime: "g:i:s A",
1042 SortableDateTime: "Y-m-d\\TH:i:s",
1043 UniversalSortableDateTime: "Y-m-d H:i:sO",
1050 var dt = new Date();
1051 document.write(dt.format(Date.patterns.ShortDate));
1056 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1057 * They generate precompiled functions from date formats instead of parsing and
1058 * processing the pattern every time you format a date. These functions are available
1059 * on every Date object (any javascript function).
1061 * The original article and download are here:
1062 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1069 Returns the number of milliseconds between this date and date
1070 @param {Date} date (optional) Defaults to now
1071 @return {Number} The diff in milliseconds
1072 @member Date getElapsed
1074 Date.prototype.getElapsed = function(date) {
1075 return Math.abs((date || new Date()).getTime()-this.getTime());
1077 // was in date file..
1081 Date.parseFunctions = {count:0};
1083 Date.parseRegexes = [];
1085 Date.formatFunctions = {count:0};
1088 Date.prototype.dateFormat = function(format) {
1089 if (Date.formatFunctions[format] == null) {
1090 Date.createNewFormat(format);
1092 var func = Date.formatFunctions[format];
1093 return this[func]();
1098 * Formats a date given the supplied format string
1099 * @param {String} format The format string
1100 * @return {String} The formatted date
1103 Date.prototype.format = Date.prototype.dateFormat;
1106 Date.createNewFormat = function(format) {
1107 var funcName = "format" + Date.formatFunctions.count++;
1108 Date.formatFunctions[format] = funcName;
1109 var code = "Date.prototype." + funcName + " = function(){return ";
1110 var special = false;
1112 for (var i = 0; i < format.length; ++i) {
1113 ch = format.charAt(i);
1114 if (!special && ch == "\\") {
1119 code += "'" + String.escape(ch) + "' + ";
1122 code += Date.getFormatCode(ch);
1125 /** eval:var:zzzzzzzzzzzzz */
1126 eval(code.substring(0, code.length - 3) + ";}");
1130 Date.getFormatCode = function(character) {
1131 switch (character) {
1133 return "String.leftPad(this.getDate(), 2, '0') + ";
1135 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1137 return "this.getDate() + ";
1139 return "Date.dayNames[this.getDay()] + ";
1141 return "this.getSuffix() + ";
1143 return "this.getDay() + ";
1145 return "this.getDayOfYear() + ";
1147 return "this.getWeekOfYear() + ";
1149 return "Date.monthNames[this.getMonth()] + ";
1151 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1153 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1155 return "(this.getMonth() + 1) + ";
1157 return "this.getDaysInMonth() + ";
1159 return "(this.isLeapYear() ? 1 : 0) + ";
1161 return "this.getFullYear() + ";
1163 return "('' + this.getFullYear()).substring(2, 4) + ";
1165 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1167 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1169 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1171 return "this.getHours() + ";
1173 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1175 return "String.leftPad(this.getHours(), 2, '0') + ";
1177 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1179 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1181 return "this.getGMTOffset() + ";
1183 return "this.getGMTColonOffset() + ";
1185 return "this.getTimezone() + ";
1187 return "(this.getTimezoneOffset() * -60) + ";
1189 return "'" + String.escape(character) + "' + ";
1194 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1195 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1196 * the date format that is not specified will default to the current date value for that part. Time parts can also
1197 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1198 * string or the parse operation will fail.
1201 //dt = Fri May 25 2007 (current date)
1202 var dt = new Date();
1204 //dt = Thu May 25 2006 (today's month/day in 2006)
1205 dt = Date.parseDate("2006", "Y");
1207 //dt = Sun Jan 15 2006 (all date parts specified)
1208 dt = Date.parseDate("2006-1-15", "Y-m-d");
1210 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1211 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1213 * @param {String} input The unparsed date as a string
1214 * @param {String} format The format the date is in
1215 * @return {Date} The parsed date
1218 Date.parseDate = function(input, format) {
1219 if (Date.parseFunctions[format] == null) {
1220 Date.createParser(format);
1222 var func = Date.parseFunctions[format];
1223 return Date[func](input);
1228 Date.createParser = function(format) {
1229 var funcName = "parse" + Date.parseFunctions.count++;
1230 var regexNum = Date.parseRegexes.length;
1231 var currentGroup = 1;
1232 Date.parseFunctions[format] = funcName;
1234 var code = "Date." + funcName + " = function(input){\n"
1235 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1236 + "var d = new Date();\n"
1237 + "y = d.getFullYear();\n"
1238 + "m = d.getMonth();\n"
1239 + "d = d.getDate();\n"
1240 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1241 + "if (results && results.length > 0) {";
1244 var special = false;
1246 for (var i = 0; i < format.length; ++i) {
1247 ch = format.charAt(i);
1248 if (!special && ch == "\\") {
1253 regex += String.escape(ch);
1256 var obj = Date.formatCodeToRegex(ch, currentGroup);
1257 currentGroup += obj.g;
1259 if (obj.g && obj.c) {
1265 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1266 + "{v = new Date(y, m, d, h, i, s);}\n"
1267 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1268 + "{v = new Date(y, m, d, h, i);}\n"
1269 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1270 + "{v = new Date(y, m, d, h);}\n"
1271 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1272 + "{v = new Date(y, m, d);}\n"
1273 + "else if (y >= 0 && m >= 0)\n"
1274 + "{v = new Date(y, m);}\n"
1275 + "else if (y >= 0)\n"
1276 + "{v = new Date(y);}\n"
1277 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1278 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1279 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1282 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1283 /** eval:var:zzzzzzzzzzzzz */
1288 Date.formatCodeToRegex = function(character, currentGroup) {
1289 switch (character) {
1293 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1296 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1297 s:"(\\d{1,2})"}; // day of month without leading zeroes
1300 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1301 s:"(\\d{2})"}; // day of month with leading zeroes
1305 s:"(?:" + Date.dayNames.join("|") + ")"};
1309 s:"(?:st|nd|rd|th)"};
1324 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1325 s:"(" + Date.monthNames.join("|") + ")"};
1328 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1329 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1332 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1333 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1336 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1337 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1348 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1352 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1353 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1357 c:"if (results[" + currentGroup + "] == 'am') {\n"
1358 + "if (h == 12) { h = 0; }\n"
1359 + "} else { if (h < 12) { h += 12; }}",
1363 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1364 + "if (h == 12) { h = 0; }\n"
1365 + "} else { if (h < 12) { h += 12; }}",
1370 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1371 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1375 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1376 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1379 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1383 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1388 "o = results[", currentGroup, "];\n",
1389 "var sn = o.substring(0,1);\n", // get + / - sign
1390 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1391 "var mn = o.substring(3,5) % 60;\n", // get minutes
1392 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1393 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1395 s:"([+\-]\\d{2,4})"};
1401 "o = results[", currentGroup, "];\n",
1402 "var sn = o.substring(0,1);\n",
1403 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1404 "var mn = o.substring(4,6) % 60;\n",
1405 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1406 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1412 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1415 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1416 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1417 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1421 s:String.escape(character)};
1426 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1427 * @return {String} The abbreviated timezone name (e.g. 'CST')
1429 Date.prototype.getTimezone = function() {
1430 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1434 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1435 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1437 Date.prototype.getGMTOffset = function() {
1438 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1439 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1440 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1444 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1445 * @return {String} 2-characters representing hours and 2-characters representing minutes
1446 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1448 Date.prototype.getGMTColonOffset = function() {
1449 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1450 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1452 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1456 * Get the numeric day number of the year, adjusted for leap year.
1457 * @return {Number} 0 through 364 (365 in leap years)
1459 Date.prototype.getDayOfYear = function() {
1461 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1462 for (var i = 0; i < this.getMonth(); ++i) {
1463 num += Date.daysInMonth[i];
1465 return num + this.getDate() - 1;
1469 * Get the string representation of the numeric week number of the year
1470 * (equivalent to the format specifier 'W').
1471 * @return {String} '00' through '52'
1473 Date.prototype.getWeekOfYear = function() {
1474 // Skip to Thursday of this week
1475 var now = this.getDayOfYear() + (4 - this.getDay());
1476 // Find the first Thursday of the year
1477 var jan1 = new Date(this.getFullYear(), 0, 1);
1478 var then = (7 - jan1.getDay() + 4);
1479 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1483 * Whether or not the current date is in a leap year.
1484 * @return {Boolean} True if the current date is in a leap year, else false
1486 Date.prototype.isLeapYear = function() {
1487 var year = this.getFullYear();
1488 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1492 * Get the first day of the current month, adjusted for leap year. The returned value
1493 * is the numeric day index within the week (0-6) which can be used in conjunction with
1494 * the {@link #monthNames} array to retrieve the textual day name.
1497 var dt = new Date('1/10/2007');
1498 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1500 * @return {Number} The day number (0-6)
1502 Date.prototype.getFirstDayOfMonth = function() {
1503 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1504 return (day < 0) ? (day + 7) : day;
1508 * Get the last day of the current month, adjusted for leap year. The returned value
1509 * is the numeric day index within the week (0-6) which can be used in conjunction with
1510 * the {@link #monthNames} array to retrieve the textual day name.
1513 var dt = new Date('1/10/2007');
1514 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1516 * @return {Number} The day number (0-6)
1518 Date.prototype.getLastDayOfMonth = function() {
1519 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1520 return (day < 0) ? (day + 7) : day;
1525 * Get the first date of this date's month
1528 Date.prototype.getFirstDateOfMonth = function() {
1529 return new Date(this.getFullYear(), this.getMonth(), 1);
1533 * Get the last date of this date's month
1536 Date.prototype.getLastDateOfMonth = function() {
1537 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1540 * Get the number of days in the current month, adjusted for leap year.
1541 * @return {Number} The number of days in the month
1543 Date.prototype.getDaysInMonth = function() {
1544 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1545 return Date.daysInMonth[this.getMonth()];
1549 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1550 * @return {String} 'st, 'nd', 'rd' or 'th'
1552 Date.prototype.getSuffix = function() {
1553 switch (this.getDate()) {
1570 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1573 * An array of textual month names.
1574 * Override these values for international dates, for example...
1575 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1594 * An array of textual day names.
1595 * Override these values for international dates, for example...
1596 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1612 Date.monthNumbers = {
1627 * Creates and returns a new Date instance with the exact same date value as the called instance.
1628 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1629 * variable will also be changed. When the intention is to create a new variable that will not
1630 * modify the original instance, you should create a clone.
1632 * Example of correctly cloning a date:
1635 var orig = new Date('10/1/2006');
1638 document.write(orig); //returns 'Thu Oct 05 2006'!
1641 var orig = new Date('10/1/2006');
1642 var copy = orig.clone();
1644 document.write(orig); //returns 'Thu Oct 01 2006'
1646 * @return {Date} The new Date instance
1648 Date.prototype.clone = function() {
1649 return new Date(this.getTime());
1653 * Clears any time information from this date
1654 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1655 @return {Date} this or the clone
1657 Date.prototype.clearTime = function(clone){
1659 return this.clone().clearTime();
1664 this.setMilliseconds(0);
1669 // safari setMonth is broken
1671 Date.brokenSetMonth = Date.prototype.setMonth;
1672 Date.prototype.setMonth = function(num){
1674 var n = Math.ceil(-num);
1675 var back_year = Math.ceil(n/12);
1676 var month = (n % 12) ? 12 - n % 12 : 0 ;
1677 this.setFullYear(this.getFullYear() - back_year);
1678 return Date.brokenSetMonth.call(this, month);
1680 return Date.brokenSetMonth.apply(this, arguments);
1685 /** Date interval constant
1689 /** Date interval constant
1693 /** Date interval constant
1697 /** Date interval constant
1701 /** Date interval constant
1705 /** Date interval constant
1709 /** Date interval constant
1715 * Provides a convenient method of performing basic date arithmetic. This method
1716 * does not modify the Date instance being called - it creates and returns
1717 * a new Date instance containing the resulting date value.
1722 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1723 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1725 //Negative values will subtract correctly:
1726 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1727 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1729 //You can even chain several calls together in one line!
1730 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1731 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1734 * @param {String} interval A valid date interval enum value
1735 * @param {Number} value The amount to add to the current date
1736 * @return {Date} The new Date instance
1738 Date.prototype.add = function(interval, value){
1739 var d = this.clone();
1740 if (!interval || value === 0) return d;
1741 switch(interval.toLowerCase()){
1743 d.setMilliseconds(this.getMilliseconds() + value);
1746 d.setSeconds(this.getSeconds() + value);
1749 d.setMinutes(this.getMinutes() + value);
1752 d.setHours(this.getHours() + value);
1755 d.setDate(this.getDate() + value);
1758 var day = this.getDate();
1760 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1763 d.setMonth(this.getMonth() + value);
1766 d.setFullYear(this.getFullYear() + value);
1773 * Ext JS Library 1.1.1
1774 * Copyright(c) 2006-2007, Ext JS, LLC.
1776 * Originally Released Under LGPL - original licence link has changed is not relivant.
1779 * <script type="text/javascript">
1783 * @class Roo.lib.Dom
1786 * Dom utils (from YIU afaik)
1791 * Get the view width
1792 * @param {Boolean} full True will get the full document, otherwise it's the view width
1793 * @return {Number} The width
1796 getViewWidth : function(full) {
1797 return full ? this.getDocumentWidth() : this.getViewportWidth();
1800 * Get the view height
1801 * @param {Boolean} full True will get the full document, otherwise it's the view height
1802 * @return {Number} The height
1804 getViewHeight : function(full) {
1805 return full ? this.getDocumentHeight() : this.getViewportHeight();
1808 getDocumentHeight: function() {
1809 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1810 return Math.max(scrollHeight, this.getViewportHeight());
1813 getDocumentWidth: function() {
1814 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1815 return Math.max(scrollWidth, this.getViewportWidth());
1818 getViewportHeight: function() {
1819 var height = self.innerHeight;
1820 var mode = document.compatMode;
1822 if ((mode || Roo.isIE) && !Roo.isOpera) {
1823 height = (mode == "CSS1Compat") ?
1824 document.documentElement.clientHeight :
1825 document.body.clientHeight;
1831 getViewportWidth: function() {
1832 var width = self.innerWidth;
1833 var mode = document.compatMode;
1835 if (mode || Roo.isIE) {
1836 width = (mode == "CSS1Compat") ?
1837 document.documentElement.clientWidth :
1838 document.body.clientWidth;
1843 isAncestor : function(p, c) {
1850 if (p.contains && !Roo.isSafari) {
1851 return p.contains(c);
1852 } else if (p.compareDocumentPosition) {
1853 return !!(p.compareDocumentPosition(c) & 16);
1855 var parent = c.parentNode;
1860 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1863 parent = parent.parentNode;
1869 getRegion : function(el) {
1870 return Roo.lib.Region.getRegion(el);
1873 getY : function(el) {
1874 return this.getXY(el)[1];
1877 getX : function(el) {
1878 return this.getXY(el)[0];
1881 getXY : function(el) {
1882 var p, pe, b, scroll, bd = document.body;
1883 el = Roo.getDom(el);
1884 var fly = Roo.lib.AnimBase.fly;
1885 if (el.getBoundingClientRect) {
1886 b = el.getBoundingClientRect();
1887 scroll = fly(document).getScroll();
1888 return [b.left + scroll.left, b.top + scroll.top];
1894 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1901 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1908 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1909 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1916 if (p != el && pe.getStyle('overflow') != 'visible') {
1924 if (Roo.isSafari && hasAbsolute) {
1929 if (Roo.isGecko && !hasAbsolute) {
1931 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1932 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1936 while (p && p != bd) {
1937 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1949 setXY : function(el, xy) {
1950 el = Roo.fly(el, '_setXY');
1952 var pts = el.translatePoints(xy);
1953 if (xy[0] !== false) {
1954 el.dom.style.left = pts.left + "px";
1956 if (xy[1] !== false) {
1957 el.dom.style.top = pts.top + "px";
1961 setX : function(el, x) {
1962 this.setXY(el, [x, false]);
1965 setY : function(el, y) {
1966 this.setXY(el, [false, y]);
1970 * Portions of this file are based on pieces of Yahoo User Interface Library
1971 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1972 * YUI licensed under the BSD License:
1973 * http://developer.yahoo.net/yui/license.txt
1974 * <script type="text/javascript">
1978 Roo.lib.Event = function() {
1979 var loadComplete = false;
1981 var unloadListeners = [];
1983 var onAvailStack = [];
1985 var lastError = null;
1998 startInterval: function() {
1999 if (!this._interval) {
2001 var callback = function() {
2002 self._tryPreloadAttach();
2004 this._interval = setInterval(callback, this.POLL_INTERVAL);
2009 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2010 onAvailStack.push({ id: p_id,
2013 override: p_override,
2014 checkReady: false });
2016 retryCount = this.POLL_RETRYS;
2017 this.startInterval();
2021 addListener: function(el, eventName, fn) {
2022 el = Roo.getDom(el);
2027 if ("unload" == eventName) {
2028 unloadListeners[unloadListeners.length] =
2029 [el, eventName, fn];
2033 var wrappedFn = function(e) {
2034 return fn(Roo.lib.Event.getEvent(e));
2037 var li = [el, eventName, fn, wrappedFn];
2039 var index = listeners.length;
2040 listeners[index] = li;
2042 this.doAdd(el, eventName, wrappedFn, false);
2048 removeListener: function(el, eventName, fn) {
2051 el = Roo.getDom(el);
2054 return this.purgeElement(el, false, eventName);
2058 if ("unload" == eventName) {
2060 for (i = 0,len = unloadListeners.length; i < len; i++) {
2061 var li = unloadListeners[i];
2064 li[1] == eventName &&
2066 unloadListeners.splice(i, 1);
2074 var cacheItem = null;
2077 var index = arguments[3];
2079 if ("undefined" == typeof index) {
2080 index = this._getCacheIndex(el, eventName, fn);
2084 cacheItem = listeners[index];
2087 if (!el || !cacheItem) {
2091 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2093 delete listeners[index][this.WFN];
2094 delete listeners[index][this.FN];
2095 listeners.splice(index, 1);
2102 getTarget: function(ev, resolveTextNode) {
2103 ev = ev.browserEvent || ev;
2104 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2105 var t = ev.target || ev.srcElement;
2106 return this.resolveTextNode(t);
2110 resolveTextNode: function(node) {
2111 if (Roo.isSafari && node && 3 == node.nodeType) {
2112 return node.parentNode;
2119 getPageX: function(ev) {
2120 ev = ev.browserEvent || ev;
2121 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2123 if (!x && 0 !== x) {
2124 x = ev.clientX || 0;
2127 x += this.getScroll()[1];
2135 getPageY: function(ev) {
2136 ev = ev.browserEvent || ev;
2137 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2139 if (!y && 0 !== y) {
2140 y = ev.clientY || 0;
2143 y += this.getScroll()[0];
2152 getXY: function(ev) {
2153 ev = ev.browserEvent || ev;
2154 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2155 return [this.getPageX(ev), this.getPageY(ev)];
2159 getRelatedTarget: function(ev) {
2160 ev = ev.browserEvent || ev;
2161 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2162 var t = ev.relatedTarget;
2164 if (ev.type == "mouseout") {
2166 } else if (ev.type == "mouseover") {
2171 return this.resolveTextNode(t);
2175 getTime: function(ev) {
2176 ev = ev.browserEvent || ev;
2177 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2179 var t = new Date().getTime();
2183 this.lastError = ex;
2192 stopEvent: function(ev) {
2193 this.stopPropagation(ev);
2194 this.preventDefault(ev);
2198 stopPropagation: function(ev) {
2199 ev = ev.browserEvent || ev;
2200 if (ev.stopPropagation) {
2201 ev.stopPropagation();
2203 ev.cancelBubble = true;
2208 preventDefault: function(ev) {
2209 ev = ev.browserEvent || ev;
2210 if(ev.preventDefault) {
2211 ev.preventDefault();
2213 ev.returnValue = false;
2218 getEvent: function(e) {
2219 var ev = e || window.event;
2221 var c = this.getEvent.caller;
2223 ev = c.arguments[0];
2224 if (ev && Event == ev.constructor) {
2234 getCharCode: function(ev) {
2235 ev = ev.browserEvent || ev;
2236 return ev.charCode || ev.keyCode || 0;
2240 _getCacheIndex: function(el, eventName, fn) {
2241 for (var i = 0,len = listeners.length; i < len; ++i) {
2242 var li = listeners[i];
2244 li[this.FN] == fn &&
2245 li[this.EL] == el &&
2246 li[this.TYPE] == eventName) {
2258 getEl: function(id) {
2259 return document.getElementById(id);
2263 clearCache: function() {
2267 _load: function(e) {
2268 loadComplete = true;
2269 var EU = Roo.lib.Event;
2273 EU.doRemove(window, "load", EU._load);
2278 _tryPreloadAttach: function() {
2287 var tryAgain = !loadComplete;
2289 tryAgain = (retryCount > 0);
2294 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2295 var item = onAvailStack[i];
2297 var el = this.getEl(item.id);
2300 if (!item.checkReady ||
2303 (document && document.body)) {
2306 if (item.override) {
2307 if (item.override === true) {
2310 scope = item.override;
2313 item.fn.call(scope, item.obj);
2314 onAvailStack[i] = null;
2317 notAvail.push(item);
2322 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2326 this.startInterval();
2328 clearInterval(this._interval);
2329 this._interval = null;
2332 this.locked = false;
2339 purgeElement: function(el, recurse, eventName) {
2340 var elListeners = this.getListeners(el, eventName);
2342 for (var i = 0,len = elListeners.length; i < len; ++i) {
2343 var l = elListeners[i];
2344 this.removeListener(el, l.type, l.fn);
2348 if (recurse && el && el.childNodes) {
2349 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2350 this.purgeElement(el.childNodes[i], recurse, eventName);
2356 getListeners: function(el, eventName) {
2357 var results = [], searchLists;
2359 searchLists = [listeners, unloadListeners];
2360 } else if (eventName == "unload") {
2361 searchLists = [unloadListeners];
2363 searchLists = [listeners];
2366 for (var j = 0; j < searchLists.length; ++j) {
2367 var searchList = searchLists[j];
2368 if (searchList && searchList.length > 0) {
2369 for (var i = 0,len = searchList.length; i < len; ++i) {
2370 var l = searchList[i];
2371 if (l && l[this.EL] === el &&
2372 (!eventName || eventName === l[this.TYPE])) {
2377 adjust: l[this.ADJ_SCOPE],
2385 return (results.length) ? results : null;
2389 _unload: function(e) {
2391 var EU = Roo.lib.Event, i, j, l, len, index;
2393 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2394 l = unloadListeners[i];
2397 if (l[EU.ADJ_SCOPE]) {
2398 if (l[EU.ADJ_SCOPE] === true) {
2401 scope = l[EU.ADJ_SCOPE];
2404 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2405 unloadListeners[i] = null;
2411 unloadListeners = null;
2413 if (listeners && listeners.length > 0) {
2414 j = listeners.length;
2417 l = listeners[index];
2419 EU.removeListener(l[EU.EL], l[EU.TYPE],
2429 EU.doRemove(window, "unload", EU._unload);
2434 getScroll: function() {
2435 var dd = document.documentElement, db = document.body;
2436 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2437 return [dd.scrollTop, dd.scrollLeft];
2439 return [db.scrollTop, db.scrollLeft];
2446 doAdd: function () {
2447 if (window.addEventListener) {
2448 return function(el, eventName, fn, capture) {
2449 el.addEventListener(eventName, fn, (capture));
2451 } else if (window.attachEvent) {
2452 return function(el, eventName, fn, capture) {
2453 el.attachEvent("on" + eventName, fn);
2462 doRemove: function() {
2463 if (window.removeEventListener) {
2464 return function (el, eventName, fn, capture) {
2465 el.removeEventListener(eventName, fn, (capture));
2467 } else if (window.detachEvent) {
2468 return function (el, eventName, fn) {
2469 el.detachEvent("on" + eventName, fn);
2481 var E = Roo.lib.Event;
2482 E.on = E.addListener;
2483 E.un = E.removeListener;
2485 if (document && document.body) {
2488 E.doAdd(window, "load", E._load);
2490 E.doAdd(window, "unload", E._unload);
2491 E._tryPreloadAttach();
2495 * Portions of this file are based on pieces of Yahoo User Interface Library
2496 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2497 * YUI licensed under the BSD License:
2498 * http://developer.yahoo.net/yui/license.txt
2499 * <script type="text/javascript">
2505 * @class Roo.lib.Ajax
2512 request : function(method, uri, cb, data, options) {
2514 var hs = options.headers;
2517 if(hs.hasOwnProperty(h)){
2518 this.initHeader(h, hs[h], false);
2522 if(options.xmlData){
2523 this.initHeader('Content-Type', 'text/xml', false);
2525 data = options.xmlData;
2529 return this.asyncRequest(method, uri, cb, data);
2532 serializeForm : function(form) {
2533 if(typeof form == 'string') {
2534 form = (document.getElementById(form) || document.forms[form]);
2537 var el, name, val, disabled, data = '', hasSubmit = false;
2538 for (var i = 0; i < form.elements.length; i++) {
2539 el = form.elements[i];
2540 disabled = form.elements[i].disabled;
2541 name = form.elements[i].name;
2542 val = form.elements[i].value;
2544 if (!disabled && name){
2548 case 'select-multiple':
2549 for (var j = 0; j < el.options.length; j++) {
2550 if (el.options[j].selected) {
2552 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2555 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2563 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2576 if(hasSubmit == false) {
2577 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2582 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2587 data = data.substr(0, data.length - 1);
2595 useDefaultHeader:true,
2597 defaultPostHeader:'application/x-www-form-urlencoded',
2599 useDefaultXhrHeader:true,
2601 defaultXhrHeader:'XMLHttpRequest',
2603 hasDefaultHeaders:true,
2615 setProgId:function(id)
2617 this.activeX.unshift(id);
2620 setDefaultPostHeader:function(b)
2622 this.useDefaultHeader = b;
2625 setDefaultXhrHeader:function(b)
2627 this.useDefaultXhrHeader = b;
2630 setPollingInterval:function(i)
2632 if (typeof i == 'number' && isFinite(i)) {
2633 this.pollInterval = i;
2637 createXhrObject:function(transactionId)
2643 http = new XMLHttpRequest();
2645 obj = { conn:http, tId:transactionId };
2649 for (var i = 0; i < this.activeX.length; ++i) {
2653 http = new ActiveXObject(this.activeX[i]);
2655 obj = { conn:http, tId:transactionId };
2668 getConnectionObject:function()
2671 var tId = this.transactionId;
2675 o = this.createXhrObject(tId);
2677 this.transactionId++;
2688 asyncRequest:function(method, uri, callback, postData)
2690 var o = this.getConnectionObject();
2696 o.conn.open(method, uri, true);
2698 if (this.useDefaultXhrHeader) {
2699 if (!this.defaultHeaders['X-Requested-With']) {
2700 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2704 if(postData && this.useDefaultHeader){
2705 this.initHeader('Content-Type', this.defaultPostHeader);
2708 if (this.hasDefaultHeaders || this.hasHeaders) {
2712 this.handleReadyState(o, callback);
2713 o.conn.send(postData || null);
2719 handleReadyState:function(o, callback)
2723 if (callback && callback.timeout) {
2725 this.timeout[o.tId] = window.setTimeout(function() {
2726 oConn.abort(o, callback, true);
2727 }, callback.timeout);
2730 this.poll[o.tId] = window.setInterval(
2732 if (o.conn && o.conn.readyState == 4) {
2733 window.clearInterval(oConn.poll[o.tId]);
2734 delete oConn.poll[o.tId];
2736 if(callback && callback.timeout) {
2737 window.clearTimeout(oConn.timeout[o.tId]);
2738 delete oConn.timeout[o.tId];
2741 oConn.handleTransactionResponse(o, callback);
2744 , this.pollInterval);
2747 handleTransactionResponse:function(o, callback, isAbort)
2751 this.releaseObject(o);
2755 var httpStatus, responseObject;
2759 if (o.conn.status !== undefined && o.conn.status != 0) {
2760 httpStatus = o.conn.status;
2772 if (httpStatus >= 200 && httpStatus < 300) {
2773 responseObject = this.createResponseObject(o, callback.argument);
2774 if (callback.success) {
2775 if (!callback.scope) {
2776 callback.success(responseObject);
2781 callback.success.apply(callback.scope, [responseObject]);
2786 switch (httpStatus) {
2794 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2795 if (callback.failure) {
2796 if (!callback.scope) {
2797 callback.failure(responseObject);
2800 callback.failure.apply(callback.scope, [responseObject]);
2805 responseObject = this.createResponseObject(o, callback.argument);
2806 if (callback.failure) {
2807 if (!callback.scope) {
2808 callback.failure(responseObject);
2811 callback.failure.apply(callback.scope, [responseObject]);
2817 this.releaseObject(o);
2818 responseObject = null;
2821 createResponseObject:function(o, callbackArg)
2828 var headerStr = o.conn.getAllResponseHeaders();
2829 var header = headerStr.split('\n');
2830 for (var i = 0; i < header.length; i++) {
2831 var delimitPos = header[i].indexOf(':');
2832 if (delimitPos != -1) {
2833 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2841 obj.status = o.conn.status;
2842 obj.statusText = o.conn.statusText;
2843 obj.getResponseHeader = headerObj;
2844 obj.getAllResponseHeaders = headerStr;
2845 obj.responseText = o.conn.responseText;
2846 obj.responseXML = o.conn.responseXML;
2848 if (typeof callbackArg !== undefined) {
2849 obj.argument = callbackArg;
2855 createExceptionObject:function(tId, callbackArg, isAbort)
2858 var COMM_ERROR = 'communication failure';
2859 var ABORT_CODE = -1;
2860 var ABORT_ERROR = 'transaction aborted';
2866 obj.status = ABORT_CODE;
2867 obj.statusText = ABORT_ERROR;
2870 obj.status = COMM_CODE;
2871 obj.statusText = COMM_ERROR;
2875 obj.argument = callbackArg;
2881 initHeader:function(label, value, isDefault)
2883 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2885 if (headerObj[label] === undefined) {
2886 headerObj[label] = value;
2891 headerObj[label] = value + "," + headerObj[label];
2895 this.hasDefaultHeaders = true;
2898 this.hasHeaders = true;
2903 setHeader:function(o)
2905 if (this.hasDefaultHeaders) {
2906 for (var prop in this.defaultHeaders) {
2907 if (this.defaultHeaders.hasOwnProperty(prop)) {
2908 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2913 if (this.hasHeaders) {
2914 for (var prop in this.headers) {
2915 if (this.headers.hasOwnProperty(prop)) {
2916 o.conn.setRequestHeader(prop, this.headers[prop]);
2920 this.hasHeaders = false;
2924 resetDefaultHeaders:function() {
2925 delete this.defaultHeaders;
2926 this.defaultHeaders = {};
2927 this.hasDefaultHeaders = false;
2930 abort:function(o, callback, isTimeout)
2932 if(this.isCallInProgress(o)) {
2934 window.clearInterval(this.poll[o.tId]);
2935 delete this.poll[o.tId];
2937 delete this.timeout[o.tId];
2940 this.handleTransactionResponse(o, callback, true);
2950 isCallInProgress:function(o)
2953 return o.conn.readyState != 4 && o.conn.readyState != 0;
2962 releaseObject:function(o)
2971 'MSXML2.XMLHTTP.3.0',
2979 * Portions of this file are based on pieces of Yahoo User Interface Library
2980 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2981 * YUI licensed under the BSD License:
2982 * http://developer.yahoo.net/yui/license.txt
2983 * <script type="text/javascript">
2987 Roo.lib.Region = function(t, r, b, l) {
2997 Roo.lib.Region.prototype = {
2998 contains : function(region) {
2999 return ( region.left >= this.left &&
3000 region.right <= this.right &&
3001 region.top >= this.top &&
3002 region.bottom <= this.bottom );
3006 getArea : function() {
3007 return ( (this.bottom - this.top) * (this.right - this.left) );
3010 intersect : function(region) {
3011 var t = Math.max(this.top, region.top);
3012 var r = Math.min(this.right, region.right);
3013 var b = Math.min(this.bottom, region.bottom);
3014 var l = Math.max(this.left, region.left);
3016 if (b >= t && r >= l) {
3017 return new Roo.lib.Region(t, r, b, l);
3022 union : function(region) {
3023 var t = Math.min(this.top, region.top);
3024 var r = Math.max(this.right, region.right);
3025 var b = Math.max(this.bottom, region.bottom);
3026 var l = Math.min(this.left, region.left);
3028 return new Roo.lib.Region(t, r, b, l);
3031 adjust : function(t, l, b, r) {
3040 Roo.lib.Region.getRegion = function(el) {
3041 var p = Roo.lib.Dom.getXY(el);
3044 var r = p[0] + el.offsetWidth;
3045 var b = p[1] + el.offsetHeight;
3048 return new Roo.lib.Region(t, r, b, l);
3051 * Portions of this file are based on pieces of Yahoo User Interface Library
3052 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3053 * YUI licensed under the BSD License:
3054 * http://developer.yahoo.net/yui/license.txt
3055 * <script type="text/javascript">
3058 //@@dep Roo.lib.Region
3061 Roo.lib.Point = function(x, y) {
3062 if (x instanceof Array) {
3066 this.x = this.right = this.left = this[0] = x;
3067 this.y = this.top = this.bottom = this[1] = y;
3070 Roo.lib.Point.prototype = new Roo.lib.Region();
3072 * Portions of this file are based on pieces of Yahoo User Interface Library
3073 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3074 * YUI licensed under the BSD License:
3075 * http://developer.yahoo.net/yui/license.txt
3076 * <script type="text/javascript">
3083 scroll : function(el, args, duration, easing, cb, scope) {
3084 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3087 motion : function(el, args, duration, easing, cb, scope) {
3088 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3091 color : function(el, args, duration, easing, cb, scope) {
3092 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3095 run : function(el, args, duration, easing, cb, scope, type) {
3096 type = type || Roo.lib.AnimBase;
3097 if (typeof easing == "string") {
3098 easing = Roo.lib.Easing[easing];
3100 var anim = new type(el, args, duration, easing);
3101 anim.animateX(function() {
3102 Roo.callback(cb, scope);
3108 * Portions of this file are based on pieces of Yahoo User Interface Library
3109 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3110 * YUI licensed under the BSD License:
3111 * http://developer.yahoo.net/yui/license.txt
3112 * <script type="text/javascript">
3120 if (!libFlyweight) {
3121 libFlyweight = new Roo.Element.Flyweight();
3123 libFlyweight.dom = el;
3124 return libFlyweight;
3127 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3131 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3133 this.init(el, attributes, duration, method);
3137 Roo.lib.AnimBase.fly = fly;
3141 Roo.lib.AnimBase.prototype = {
3143 toString: function() {
3144 var el = this.getEl();
3145 var id = el.id || el.tagName;
3146 return ("Anim " + id);
3150 noNegatives: /width|height|opacity|padding/i,
3151 offsetAttribute: /^((width|height)|(top|left))$/,
3152 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3153 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3157 doMethod: function(attr, start, end) {
3158 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3162 setAttribute: function(attr, val, unit) {
3163 if (this.patterns.noNegatives.test(attr)) {
3164 val = (val > 0) ? val : 0;
3167 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3171 getAttribute: function(attr) {
3172 var el = this.getEl();
3173 var val = fly(el).getStyle(attr);
3175 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3176 return parseFloat(val);
3179 var a = this.patterns.offsetAttribute.exec(attr) || [];
3180 var pos = !!( a[3] );
3181 var box = !!( a[2] );
3184 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3185 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3194 getDefaultUnit: function(attr) {
3195 if (this.patterns.defaultUnit.test(attr)) {
3202 animateX : function(callback, scope) {
3203 var f = function() {
3204 this.onComplete.removeListener(f);
3205 if (typeof callback == "function") {
3206 callback.call(scope || this, this);
3209 this.onComplete.addListener(f, this);
3214 setRuntimeAttribute: function(attr) {
3217 var attributes = this.attributes;
3219 this.runtimeAttributes[attr] = {};
3221 var isset = function(prop) {
3222 return (typeof prop !== 'undefined');
3225 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3229 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3232 if (isset(attributes[attr]['to'])) {
3233 end = attributes[attr]['to'];
3234 } else if (isset(attributes[attr]['by'])) {
3235 if (start.constructor == Array) {
3237 for (var i = 0, len = start.length; i < len; ++i) {
3238 end[i] = start[i] + attributes[attr]['by'][i];
3241 end = start + attributes[attr]['by'];
3245 this.runtimeAttributes[attr].start = start;
3246 this.runtimeAttributes[attr].end = end;
3249 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3253 init: function(el, attributes, duration, method) {
3255 var isAnimated = false;
3258 var startTime = null;
3261 var actualFrames = 0;
3264 el = Roo.getDom(el);
3267 this.attributes = attributes || {};
3270 this.duration = duration || 1;
3273 this.method = method || Roo.lib.Easing.easeNone;
3276 this.useSeconds = true;
3279 this.currentFrame = 0;
3282 this.totalFrames = Roo.lib.AnimMgr.fps;
3285 this.getEl = function() {
3290 this.isAnimated = function() {
3295 this.getStartTime = function() {
3299 this.runtimeAttributes = {};
3302 this.animate = function() {
3303 if (this.isAnimated()) {
3307 this.currentFrame = 0;
3309 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3311 Roo.lib.AnimMgr.registerElement(this);
3315 this.stop = function(finish) {
3317 this.currentFrame = this.totalFrames;
3318 this._onTween.fire();
3320 Roo.lib.AnimMgr.stop(this);
3323 var onStart = function() {
3324 this.onStart.fire();
3326 this.runtimeAttributes = {};
3327 for (var attr in this.attributes) {
3328 this.setRuntimeAttribute(attr);
3333 startTime = new Date();
3337 var onTween = function() {
3339 duration: new Date() - this.getStartTime(),
3340 currentFrame: this.currentFrame
3343 data.toString = function() {
3345 'duration: ' + data.duration +
3346 ', currentFrame: ' + data.currentFrame
3350 this.onTween.fire(data);
3352 var runtimeAttributes = this.runtimeAttributes;
3354 for (var attr in runtimeAttributes) {
3355 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3361 var onComplete = function() {
3362 var actual_duration = (new Date() - startTime) / 1000 ;
3365 duration: actual_duration,
3366 frames: actualFrames,
3367 fps: actualFrames / actual_duration
3370 data.toString = function() {
3372 'duration: ' + data.duration +
3373 ', frames: ' + data.frames +
3374 ', fps: ' + data.fps
3380 this.onComplete.fire(data);
3384 this._onStart = new Roo.util.Event(this);
3385 this.onStart = new Roo.util.Event(this);
3386 this.onTween = new Roo.util.Event(this);
3387 this._onTween = new Roo.util.Event(this);
3388 this.onComplete = new Roo.util.Event(this);
3389 this._onComplete = new Roo.util.Event(this);
3390 this._onStart.addListener(onStart);
3391 this._onTween.addListener(onTween);
3392 this._onComplete.addListener(onComplete);
3397 * Portions of this file are based on pieces of Yahoo User Interface Library
3398 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3399 * YUI licensed under the BSD License:
3400 * http://developer.yahoo.net/yui/license.txt
3401 * <script type="text/javascript">
3405 Roo.lib.AnimMgr = new function() {
3422 this.registerElement = function(tween) {
3423 queue[queue.length] = tween;
3425 tween._onStart.fire();
3430 this.unRegister = function(tween, index) {
3431 tween._onComplete.fire();
3432 index = index || getIndex(tween);
3434 queue.splice(index, 1);
3438 if (tweenCount <= 0) {
3444 this.start = function() {
3445 if (thread === null) {
3446 thread = setInterval(this.run, this.delay);
3451 this.stop = function(tween) {
3453 clearInterval(thread);
3455 for (var i = 0, len = queue.length; i < len; ++i) {
3456 if (queue[0].isAnimated()) {
3457 this.unRegister(queue[0], 0);
3466 this.unRegister(tween);
3471 this.run = function() {
3472 for (var i = 0, len = queue.length; i < len; ++i) {
3473 var tween = queue[i];
3474 if (!tween || !tween.isAnimated()) {
3478 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3480 tween.currentFrame += 1;
3482 if (tween.useSeconds) {
3483 correctFrame(tween);
3485 tween._onTween.fire();
3488 Roo.lib.AnimMgr.stop(tween, i);
3493 var getIndex = function(anim) {
3494 for (var i = 0, len = queue.length; i < len; ++i) {
3495 if (queue[i] == anim) {
3503 var correctFrame = function(tween) {
3504 var frames = tween.totalFrames;
3505 var frame = tween.currentFrame;
3506 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3507 var elapsed = (new Date() - tween.getStartTime());
3510 if (elapsed < tween.duration * 1000) {
3511 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3513 tweak = frames - (frame + 1);
3515 if (tweak > 0 && isFinite(tweak)) {
3516 if (tween.currentFrame + tweak >= frames) {
3517 tweak = frames - (frame + 1);
3520 tween.currentFrame += tweak;
3526 * Portions of this file are based on pieces of Yahoo User Interface Library
3527 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3528 * YUI licensed under the BSD License:
3529 * http://developer.yahoo.net/yui/license.txt
3530 * <script type="text/javascript">
3533 Roo.lib.Bezier = new function() {
3535 this.getPosition = function(points, t) {
3536 var n = points.length;
3539 for (var i = 0; i < n; ++i) {
3540 tmp[i] = [points[i][0], points[i][1]];
3543 for (var j = 1; j < n; ++j) {
3544 for (i = 0; i < n - j; ++i) {
3545 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3546 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3550 return [ tmp[0][0], tmp[0][1] ];
3554 * Portions of this file are based on pieces of Yahoo User Interface Library
3555 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3556 * YUI licensed under the BSD License:
3557 * http://developer.yahoo.net/yui/license.txt
3558 * <script type="text/javascript">
3563 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3564 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3567 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3569 var fly = Roo.lib.AnimBase.fly;
3571 var superclass = Y.ColorAnim.superclass;
3572 var proto = Y.ColorAnim.prototype;
3574 proto.toString = function() {
3575 var el = this.getEl();
3576 var id = el.id || el.tagName;
3577 return ("ColorAnim " + id);
3580 proto.patterns.color = /color$/i;
3581 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3582 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3583 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3584 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3587 proto.parseColor = function(s) {
3588 if (s.length == 3) {
3592 var c = this.patterns.hex.exec(s);
3593 if (c && c.length == 4) {
3594 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3597 c = this.patterns.rgb.exec(s);
3598 if (c && c.length == 4) {
3599 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3602 c = this.patterns.hex3.exec(s);
3603 if (c && c.length == 4) {
3604 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3609 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3610 proto.getAttribute = function(attr) {
3611 var el = this.getEl();
3612 if (this.patterns.color.test(attr)) {
3613 var val = fly(el).getStyle(attr);
3615 if (this.patterns.transparent.test(val)) {
3616 var parent = el.parentNode;
3617 val = fly(parent).getStyle(attr);
3619 while (parent && this.patterns.transparent.test(val)) {
3620 parent = parent.parentNode;
3621 val = fly(parent).getStyle(attr);
3622 if (parent.tagName.toUpperCase() == 'HTML') {
3628 val = superclass.getAttribute.call(this, attr);
3633 proto.getAttribute = function(attr) {
3634 var el = this.getEl();
3635 if (this.patterns.color.test(attr)) {
3636 var val = fly(el).getStyle(attr);
3638 if (this.patterns.transparent.test(val)) {
3639 var parent = el.parentNode;
3640 val = fly(parent).getStyle(attr);
3642 while (parent && this.patterns.transparent.test(val)) {
3643 parent = parent.parentNode;
3644 val = fly(parent).getStyle(attr);
3645 if (parent.tagName.toUpperCase() == 'HTML') {
3651 val = superclass.getAttribute.call(this, attr);
3657 proto.doMethod = function(attr, start, end) {
3660 if (this.patterns.color.test(attr)) {
3662 for (var i = 0, len = start.length; i < len; ++i) {
3663 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3666 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3669 val = superclass.doMethod.call(this, attr, start, end);
3675 proto.setRuntimeAttribute = function(attr) {
3676 superclass.setRuntimeAttribute.call(this, attr);
3678 if (this.patterns.color.test(attr)) {
3679 var attributes = this.attributes;
3680 var start = this.parseColor(this.runtimeAttributes[attr].start);
3681 var end = this.parseColor(this.runtimeAttributes[attr].end);
3683 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3684 end = this.parseColor(attributes[attr].by);
3686 for (var i = 0, len = start.length; i < len; ++i) {
3687 end[i] = start[i] + end[i];
3691 this.runtimeAttributes[attr].start = start;
3692 this.runtimeAttributes[attr].end = end;
3698 * Portions of this file are based on pieces of Yahoo User Interface Library
3699 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3700 * YUI licensed under the BSD License:
3701 * http://developer.yahoo.net/yui/license.txt
3702 * <script type="text/javascript">
3708 easeNone: function (t, b, c, d) {
3709 return c * t / d + b;
3713 easeIn: function (t, b, c, d) {
3714 return c * (t /= d) * t + b;
3718 easeOut: function (t, b, c, d) {
3719 return -c * (t /= d) * (t - 2) + b;
3723 easeBoth: function (t, b, c, d) {
3724 if ((t /= d / 2) < 1) {
3725 return c / 2 * t * t + b;
3728 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3732 easeInStrong: function (t, b, c, d) {
3733 return c * (t /= d) * t * t * t + b;
3737 easeOutStrong: function (t, b, c, d) {
3738 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3742 easeBothStrong: function (t, b, c, d) {
3743 if ((t /= d / 2) < 1) {
3744 return c / 2 * t * t * t * t + b;
3747 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3752 elasticIn: function (t, b, c, d, a, p) {
3756 if ((t /= d) == 1) {
3763 if (!a || a < Math.abs(c)) {
3768 var s = p / (2 * Math.PI) * Math.asin(c / a);
3771 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3775 elasticOut: function (t, b, c, d, a, p) {
3779 if ((t /= d) == 1) {
3786 if (!a || a < Math.abs(c)) {
3791 var s = p / (2 * Math.PI) * Math.asin(c / a);
3794 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3798 elasticBoth: function (t, b, c, d, a, p) {
3803 if ((t /= d / 2) == 2) {
3811 if (!a || a < Math.abs(c)) {
3816 var s = p / (2 * Math.PI) * Math.asin(c / a);
3820 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3821 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3823 return a * Math.pow(2, -10 * (t -= 1)) *
3824 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3829 backIn: function (t, b, c, d, s) {
3830 if (typeof s == 'undefined') {
3833 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3837 backOut: function (t, b, c, d, s) {
3838 if (typeof s == 'undefined') {
3841 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3845 backBoth: function (t, b, c, d, s) {
3846 if (typeof s == 'undefined') {
3850 if ((t /= d / 2 ) < 1) {
3851 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3853 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3857 bounceIn: function (t, b, c, d) {
3858 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3862 bounceOut: function (t, b, c, d) {
3863 if ((t /= d) < (1 / 2.75)) {
3864 return c * (7.5625 * t * t) + b;
3865 } else if (t < (2 / 2.75)) {
3866 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3867 } else if (t < (2.5 / 2.75)) {
3868 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3870 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3874 bounceBoth: function (t, b, c, d) {
3876 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3878 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3881 * Portions of this file are based on pieces of Yahoo User Interface Library
3882 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3883 * YUI licensed under the BSD License:
3884 * http://developer.yahoo.net/yui/license.txt
3885 * <script type="text/javascript">
3889 Roo.lib.Motion = function(el, attributes, duration, method) {
3891 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3895 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3899 var superclass = Y.Motion.superclass;
3900 var proto = Y.Motion.prototype;
3902 proto.toString = function() {
3903 var el = this.getEl();
3904 var id = el.id || el.tagName;
3905 return ("Motion " + id);
3908 proto.patterns.points = /^points$/i;
3910 proto.setAttribute = function(attr, val, unit) {
3911 if (this.patterns.points.test(attr)) {
3912 unit = unit || 'px';
3913 superclass.setAttribute.call(this, 'left', val[0], unit);
3914 superclass.setAttribute.call(this, 'top', val[1], unit);
3916 superclass.setAttribute.call(this, attr, val, unit);
3920 proto.getAttribute = function(attr) {
3921 if (this.patterns.points.test(attr)) {
3923 superclass.getAttribute.call(this, 'left'),
3924 superclass.getAttribute.call(this, 'top')
3927 val = superclass.getAttribute.call(this, attr);
3933 proto.doMethod = function(attr, start, end) {
3936 if (this.patterns.points.test(attr)) {
3937 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3938 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3940 val = superclass.doMethod.call(this, attr, start, end);
3945 proto.setRuntimeAttribute = function(attr) {
3946 if (this.patterns.points.test(attr)) {
3947 var el = this.getEl();
3948 var attributes = this.attributes;
3950 var control = attributes['points']['control'] || [];
3954 if (control.length > 0 && !(control[0] instanceof Array)) {
3955 control = [control];
3958 for (i = 0,len = control.length; i < len; ++i) {
3959 tmp[i] = control[i];
3964 Roo.fly(el).position();
3966 if (isset(attributes['points']['from'])) {
3967 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3970 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3973 start = this.getAttribute('points');
3976 if (isset(attributes['points']['to'])) {
3977 end = translateValues.call(this, attributes['points']['to'], start);
3979 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3980 for (i = 0,len = control.length; i < len; ++i) {
3981 control[i] = translateValues.call(this, control[i], start);
3985 } else if (isset(attributes['points']['by'])) {
3986 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3988 for (i = 0,len = control.length; i < len; ++i) {
3989 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3993 this.runtimeAttributes[attr] = [start];
3995 if (control.length > 0) {
3996 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3999 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4002 superclass.setRuntimeAttribute.call(this, attr);
4006 var translateValues = function(val, start) {
4007 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4008 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4013 var isset = function(prop) {
4014 return (typeof prop !== 'undefined');
4018 * Portions of this file are based on pieces of Yahoo User Interface Library
4019 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4020 * YUI licensed under the BSD License:
4021 * http://developer.yahoo.net/yui/license.txt
4022 * <script type="text/javascript">
4026 Roo.lib.Scroll = function(el, attributes, duration, method) {
4028 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4032 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4036 var superclass = Y.Scroll.superclass;
4037 var proto = Y.Scroll.prototype;
4039 proto.toString = function() {
4040 var el = this.getEl();
4041 var id = el.id || el.tagName;
4042 return ("Scroll " + id);
4045 proto.doMethod = function(attr, start, end) {
4048 if (attr == 'scroll') {
4050 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4051 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4055 val = superclass.doMethod.call(this, attr, start, end);
4060 proto.getAttribute = function(attr) {
4062 var el = this.getEl();
4064 if (attr == 'scroll') {
4065 val = [ el.scrollLeft, el.scrollTop ];
4067 val = superclass.getAttribute.call(this, attr);
4073 proto.setAttribute = function(attr, val, unit) {
4074 var el = this.getEl();
4076 if (attr == 'scroll') {
4077 el.scrollLeft = val[0];
4078 el.scrollTop = val[1];
4080 superclass.setAttribute.call(this, attr, val, unit);
4086 * Ext JS Library 1.1.1
4087 * Copyright(c) 2006-2007, Ext JS, LLC.
4089 * Originally Released Under LGPL - original licence link has changed is not relivant.
4092 * <script type="text/javascript">
4096 // nasty IE9 hack - what a pile of crap that is..
4098 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4099 Range.prototype.createContextualFragment = function (html) {
4100 var doc = window.document;
4101 var container = doc.createElement("div");
4102 container.innerHTML = html;
4103 var frag = doc.createDocumentFragment(), n;
4104 while ((n = container.firstChild)) {
4105 frag.appendChild(n);
4112 * @class Roo.DomHelper
4113 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4114 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4117 Roo.DomHelper = function(){
4118 var tempTableEl = null;
4119 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4120 var tableRe = /^table|tbody|tr|td$/i;
4122 // build as innerHTML where available
4124 var createHtml = function(o){
4125 if(typeof o == 'string'){
4134 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4135 if(attr == "style"){
4137 if(typeof s == "function"){
4140 if(typeof s == "string"){
4141 b += ' style="' + s + '"';
4142 }else if(typeof s == "object"){
4145 if(typeof s[key] != "function"){
4146 b += key + ":" + s[key] + ";";
4153 b += ' class="' + o["cls"] + '"';
4154 }else if(attr == "htmlFor"){
4155 b += ' for="' + o["htmlFor"] + '"';
4157 b += " " + attr + '="' + o[attr] + '"';
4161 if(emptyTags.test(o.tag)){
4165 var cn = o.children || o.cn;
4167 //http://bugs.kde.org/show_bug.cgi?id=71506
4168 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4169 for(var i = 0, len = cn.length; i < len; i++) {
4170 b += createHtml(cn[i], b);
4173 b += createHtml(cn, b);
4179 b += "</" + o.tag + ">";
4186 var createDom = function(o, parentNode){
4188 // defininition craeted..
4190 if (o.ns && o.ns != 'html') {
4192 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4193 xmlns[o.ns] = o.xmlns;
4196 if (typeof(xmlns[o.ns]) == 'undefined') {
4197 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4203 if (typeof(o) == 'string') {
4204 return parentNode.appendChild(document.createTextNode(o));
4206 o.tag = o.tag || div;
4207 if (o.ns && Roo.isIE) {
4209 o.tag = o.ns + ':' + o.tag;
4212 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4213 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4216 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4217 attr == "style" || typeof o[attr] == "function") continue;
4219 if(attr=="cls" && Roo.isIE){
4220 el.className = o["cls"];
4222 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4223 else el[attr] = o[attr];
4226 Roo.DomHelper.applyStyles(el, o.style);
4227 var cn = o.children || o.cn;
4229 //http://bugs.kde.org/show_bug.cgi?id=71506
4230 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4231 for(var i = 0, len = cn.length; i < len; i++) {
4232 createDom(cn[i], el);
4239 el.innerHTML = o.html;
4242 parentNode.appendChild(el);
4247 var ieTable = function(depth, s, h, e){
4248 tempTableEl.innerHTML = [s, h, e].join('');
4249 var i = -1, el = tempTableEl;
4256 // kill repeat to save bytes
4260 tbe = '</tbody>'+te,
4266 * Nasty code for IE's broken table implementation
4268 var insertIntoTable = function(tag, where, el, html){
4270 tempTableEl = document.createElement('div');
4275 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4278 if(where == 'beforebegin'){
4282 before = el.nextSibling;
4285 node = ieTable(4, trs, html, tre);
4287 else if(tag == 'tr'){
4288 if(where == 'beforebegin'){
4291 node = ieTable(3, tbs, html, tbe);
4292 } else if(where == 'afterend'){
4293 before = el.nextSibling;
4295 node = ieTable(3, tbs, html, tbe);
4296 } else{ // INTO a TR
4297 if(where == 'afterbegin'){
4298 before = el.firstChild;
4300 node = ieTable(4, trs, html, tre);
4302 } else if(tag == 'tbody'){
4303 if(where == 'beforebegin'){
4306 node = ieTable(2, ts, html, te);
4307 } else if(where == 'afterend'){
4308 before = el.nextSibling;
4310 node = ieTable(2, ts, html, te);
4312 if(where == 'afterbegin'){
4313 before = el.firstChild;
4315 node = ieTable(3, tbs, html, tbe);
4318 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4321 if(where == 'afterbegin'){
4322 before = el.firstChild;
4324 node = ieTable(2, ts, html, te);
4326 el.insertBefore(node, before);
4331 /** True to force the use of DOM instead of html fragments @type Boolean */
4335 * Returns the markup for the passed Element(s) config
4336 * @param {Object} o The Dom object spec (and children)
4339 markup : function(o){
4340 return createHtml(o);
4344 * Applies a style specification to an element
4345 * @param {String/HTMLElement} el The element to apply styles to
4346 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4347 * a function which returns such a specification.
4349 applyStyles : function(el, styles){
4352 if(typeof styles == "string"){
4353 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4355 while ((matches = re.exec(styles)) != null){
4356 el.setStyle(matches[1], matches[2]);
4358 }else if (typeof styles == "object"){
4359 for (var style in styles){
4360 el.setStyle(style, styles[style]);
4362 }else if (typeof styles == "function"){
4363 Roo.DomHelper.applyStyles(el, styles.call());
4369 * Inserts an HTML fragment into the Dom
4370 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4371 * @param {HTMLElement} el The context element
4372 * @param {String} html The HTML fragmenet
4373 * @return {HTMLElement} The new node
4375 insertHtml : function(where, el, html){
4376 where = where.toLowerCase();
4377 if(el.insertAdjacentHTML){
4378 if(tableRe.test(el.tagName)){
4380 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4386 el.insertAdjacentHTML('BeforeBegin', html);
4387 return el.previousSibling;
4389 el.insertAdjacentHTML('AfterBegin', html);
4390 return el.firstChild;
4392 el.insertAdjacentHTML('BeforeEnd', html);
4393 return el.lastChild;
4395 el.insertAdjacentHTML('AfterEnd', html);
4396 return el.nextSibling;
4398 throw 'Illegal insertion point -> "' + where + '"';
4400 var range = el.ownerDocument.createRange();
4404 range.setStartBefore(el);
4405 frag = range.createContextualFragment(html);
4406 el.parentNode.insertBefore(frag, el);
4407 return el.previousSibling;
4410 range.setStartBefore(el.firstChild);
4411 frag = range.createContextualFragment(html);
4412 el.insertBefore(frag, el.firstChild);
4413 return el.firstChild;
4415 el.innerHTML = html;
4416 return el.firstChild;
4420 range.setStartAfter(el.lastChild);
4421 frag = range.createContextualFragment(html);
4422 el.appendChild(frag);
4423 return el.lastChild;
4425 el.innerHTML = html;
4426 return el.lastChild;
4429 range.setStartAfter(el);
4430 frag = range.createContextualFragment(html);
4431 el.parentNode.insertBefore(frag, el.nextSibling);
4432 return el.nextSibling;
4434 throw 'Illegal insertion point -> "' + where + '"';
4438 * Creates new Dom element(s) and inserts them before el
4439 * @param {String/HTMLElement/Element} el The context element
4440 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4441 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4442 * @return {HTMLElement/Roo.Element} The new node
4444 insertBefore : function(el, o, returnElement){
4445 return this.doInsert(el, o, returnElement, "beforeBegin");
4449 * Creates new Dom element(s) and inserts them after el
4450 * @param {String/HTMLElement/Element} el The context element
4451 * @param {Object} o The Dom object spec (and children)
4452 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4453 * @return {HTMLElement/Roo.Element} The new node
4455 insertAfter : function(el, o, returnElement){
4456 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4460 * Creates new Dom element(s) and inserts them as the first child of el
4461 * @param {String/HTMLElement/Element} el The context element
4462 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4463 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4464 * @return {HTMLElement/Roo.Element} The new node
4466 insertFirst : function(el, o, returnElement){
4467 return this.doInsert(el, o, returnElement, "afterBegin");
4471 doInsert : function(el, o, returnElement, pos, sibling){
4472 el = Roo.getDom(el);
4474 if(this.useDom || o.ns){
4475 newNode = createDom(o, null);
4476 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4478 var html = createHtml(o);
4479 newNode = this.insertHtml(pos, el, html);
4481 return returnElement ? Roo.get(newNode, true) : newNode;
4485 * Creates new Dom element(s) and appends them to el
4486 * @param {String/HTMLElement/Element} el The context element
4487 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4488 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4489 * @return {HTMLElement/Roo.Element} The new node
4491 append : function(el, o, returnElement){
4492 el = Roo.getDom(el);
4494 if(this.useDom || o.ns){
4495 newNode = createDom(o, null);
4496 el.appendChild(newNode);
4498 var html = createHtml(o);
4499 newNode = this.insertHtml("beforeEnd", el, html);
4501 return returnElement ? Roo.get(newNode, true) : newNode;
4505 * Creates new Dom element(s) and overwrites the contents of el with them
4506 * @param {String/HTMLElement/Element} el The context element
4507 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4508 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4509 * @return {HTMLElement/Roo.Element} The new node
4511 overwrite : function(el, o, returnElement){
4512 el = Roo.getDom(el);
4515 while (el.childNodes.length) {
4516 el.removeChild(el.firstChild);
4520 el.innerHTML = createHtml(o);
4523 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4527 * Creates a new Roo.DomHelper.Template from the Dom object spec
4528 * @param {Object} o The Dom object spec (and children)
4529 * @return {Roo.DomHelper.Template} The new template
4531 createTemplate : function(o){
4532 var html = createHtml(o);
4533 return new Roo.Template(html);
4539 * Ext JS Library 1.1.1
4540 * Copyright(c) 2006-2007, Ext JS, LLC.
4542 * Originally Released Under LGPL - original licence link has changed is not relivant.
4545 * <script type="text/javascript">
4549 * @class Roo.Template
4550 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4551 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4554 var t = new Roo.Template({
4555 html : '<div name="{id}">' +
4556 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4558 myformat: function (value, allValues) {
4559 return 'XX' + value;
4562 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4564 * For more information see this blog post with examples:
4565 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4566 - Create Elements using DOM, HTML fragments and Templates</a>.
4568 * @param {Object} cfg - Configuration object.
4570 Roo.Template = function(cfg){
4572 if(cfg instanceof Array){
4574 }else if(arguments.length > 1){
4575 cfg = Array.prototype.join.call(arguments, "");
4579 if (typeof(cfg) == 'object') {
4590 Roo.Template.prototype = {
4593 * @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..
4594 * it should be fixed so that template is observable...
4598 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4602 * Returns an HTML fragment of this template with the specified values applied.
4603 * @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'})
4604 * @return {String} The HTML fragment
4606 applyTemplate : function(values){
4610 return this.compiled(values);
4612 var useF = this.disableFormats !== true;
4613 var fm = Roo.util.Format, tpl = this;
4614 var fn = function(m, name, format, args){
4616 if(format.substr(0, 5) == "this."){
4617 return tpl.call(format.substr(5), values[name], values);
4620 // quoted values are required for strings in compiled templates,
4621 // but for non compiled we need to strip them
4622 // quoted reversed for jsmin
4623 var re = /^\s*['"](.*)["']\s*$/;
4624 args = args.split(',');
4625 for(var i = 0, len = args.length; i < len; i++){
4626 args[i] = args[i].replace(re, "$1");
4628 args = [values[name]].concat(args);
4630 args = [values[name]];
4632 return fm[format].apply(fm, args);
4635 return values[name] !== undefined ? values[name] : "";
4638 return this.html.replace(this.re, fn);
4656 this.loading = true;
4657 this.compiled = false;
4659 var cx = new Roo.data.Connection();
4663 success : function (response) {
4665 _t.html = response.responseText;
4669 failure : function(response) {
4670 Roo.log("Template failed to load from " + _t.url);
4677 * Sets the HTML used as the template and optionally compiles it.
4678 * @param {String} html
4679 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4680 * @return {Roo.Template} this
4682 set : function(html, compile){
4684 this.compiled = null;
4692 * True to disable format functions (defaults to false)
4695 disableFormats : false,
4698 * The regular expression used to match template variables
4702 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4705 * Compiles the template into an internal function, eliminating the RegEx overhead.
4706 * @return {Roo.Template} this
4708 compile : function(){
4709 var fm = Roo.util.Format;
4710 var useF = this.disableFormats !== true;
4711 var sep = Roo.isGecko ? "+" : ",";
4712 var fn = function(m, name, format, args){
4714 args = args ? ',' + args : "";
4715 if(format.substr(0, 5) != "this."){
4716 format = "fm." + format + '(';
4718 format = 'this.call("'+ format.substr(5) + '", ';
4722 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4724 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4727 // branched to use + in gecko and [].join() in others
4729 body = "this.compiled = function(values){ return '" +
4730 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4733 body = ["this.compiled = function(values){ return ['"];
4734 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4735 body.push("'].join('');};");
4736 body = body.join('');
4746 // private function used to call members
4747 call : function(fnName, value, allValues){
4748 return this[fnName](value, allValues);
4752 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4753 * @param {String/HTMLElement/Roo.Element} el The context element
4754 * @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'})
4755 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4756 * @return {HTMLElement/Roo.Element} The new node or Element
4758 insertFirst: function(el, values, returnElement){
4759 return this.doInsert('afterBegin', el, values, returnElement);
4763 * Applies the supplied values to the template and inserts the new node(s) before el.
4764 * @param {String/HTMLElement/Roo.Element} el The context element
4765 * @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'})
4766 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4767 * @return {HTMLElement/Roo.Element} The new node or Element
4769 insertBefore: function(el, values, returnElement){
4770 return this.doInsert('beforeBegin', el, values, returnElement);
4774 * Applies the supplied values to the template and inserts the new node(s) after el.
4775 * @param {String/HTMLElement/Roo.Element} el The context element
4776 * @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'})
4777 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4778 * @return {HTMLElement/Roo.Element} The new node or Element
4780 insertAfter : function(el, values, returnElement){
4781 return this.doInsert('afterEnd', el, values, returnElement);
4785 * Applies the supplied values to the template and appends the new node(s) to el.
4786 * @param {String/HTMLElement/Roo.Element} el The context element
4787 * @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'})
4788 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4789 * @return {HTMLElement/Roo.Element} The new node or Element
4791 append : function(el, values, returnElement){
4792 return this.doInsert('beforeEnd', el, values, returnElement);
4795 doInsert : function(where, el, values, returnEl){
4796 el = Roo.getDom(el);
4797 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4798 return returnEl ? Roo.get(newNode, true) : newNode;
4802 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4803 * @param {String/HTMLElement/Roo.Element} el The context element
4804 * @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'})
4805 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4806 * @return {HTMLElement/Roo.Element} The new node or Element
4808 overwrite : function(el, values, returnElement){
4809 el = Roo.getDom(el);
4810 el.innerHTML = this.applyTemplate(values);
4811 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4815 * Alias for {@link #applyTemplate}
4818 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4821 Roo.DomHelper.Template = Roo.Template;
4824 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4825 * @param {String/HTMLElement} el A DOM element or its id
4826 * @returns {Roo.Template} The created template
4829 Roo.Template.from = function(el){
4830 el = Roo.getDom(el);
4831 return new Roo.Template(el.value || el.innerHTML);
4834 * Ext JS Library 1.1.1
4835 * Copyright(c) 2006-2007, Ext JS, LLC.
4837 * Originally Released Under LGPL - original licence link has changed is not relivant.
4840 * <script type="text/javascript">
4845 * This is code is also distributed under MIT license for use
4846 * with jQuery and prototype JavaScript libraries.
4849 * @class Roo.DomQuery
4850 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).
4852 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>
4855 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.
4857 <h4>Element Selectors:</h4>
4859 <li> <b>*</b> any element</li>
4860 <li> <b>E</b> an element with the tag E</li>
4861 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4862 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4863 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4864 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4866 <h4>Attribute Selectors:</h4>
4867 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4869 <li> <b>E[foo]</b> has an attribute "foo"</li>
4870 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4871 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4872 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4873 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4874 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4875 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4877 <h4>Pseudo Classes:</h4>
4879 <li> <b>E:first-child</b> E is the first child of its parent</li>
4880 <li> <b>E:last-child</b> E is the last child of its parent</li>
4881 <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>
4882 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4883 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4884 <li> <b>E:only-child</b> E is the only child of its parent</li>
4885 <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>
4886 <li> <b>E:first</b> the first E in the resultset</li>
4887 <li> <b>E:last</b> the last E in the resultset</li>
4888 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4889 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4890 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4891 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4892 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4893 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4894 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4895 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4896 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4898 <h4>CSS Value Selectors:</h4>
4900 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4901 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4902 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4903 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4904 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4905 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4909 Roo.DomQuery = function(){
4910 var cache = {}, simpleCache = {}, valueCache = {};
4911 var nonSpace = /\S/;
4912 var trimRe = /^\s+|\s+$/g;
4913 var tplRe = /\{(\d+)\}/g;
4914 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4915 var tagTokenRe = /^(#)?([\w-\*]+)/;
4916 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4918 function child(p, index){
4920 var n = p.firstChild;
4922 if(n.nodeType == 1){
4933 while((n = n.nextSibling) && n.nodeType != 1);
4938 while((n = n.previousSibling) && n.nodeType != 1);
4942 function children(d){
4943 var n = d.firstChild, ni = -1;
4945 var nx = n.nextSibling;
4946 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4956 function byClassName(c, a, v){
4960 var r = [], ri = -1, cn;
4961 for(var i = 0, ci; ci = c[i]; i++){
4962 if((' '+ci.className+' ').indexOf(v) != -1){
4969 function attrValue(n, attr){
4970 if(!n.tagName && typeof n.length != "undefined"){
4979 if(attr == "class" || attr == "className"){
4982 return n.getAttribute(attr) || n[attr];
4986 function getNodes(ns, mode, tagName){
4987 var result = [], ri = -1, cs;
4991 tagName = tagName || "*";
4992 if(typeof ns.getElementsByTagName != "undefined"){
4996 for(var i = 0, ni; ni = ns[i]; i++){
4997 cs = ni.getElementsByTagName(tagName);
4998 for(var j = 0, ci; ci = cs[j]; j++){
5002 }else if(mode == "/" || mode == ">"){
5003 var utag = tagName.toUpperCase();
5004 for(var i = 0, ni, cn; ni = ns[i]; i++){
5005 cn = ni.children || ni.childNodes;
5006 for(var j = 0, cj; cj = cn[j]; j++){
5007 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5012 }else if(mode == "+"){
5013 var utag = tagName.toUpperCase();
5014 for(var i = 0, n; n = ns[i]; i++){
5015 while((n = n.nextSibling) && n.nodeType != 1);
5016 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5020 }else if(mode == "~"){
5021 for(var i = 0, n; n = ns[i]; i++){
5022 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5031 function concat(a, b){
5035 for(var i = 0, l = b.length; i < l; i++){
5041 function byTag(cs, tagName){
5042 if(cs.tagName || cs == document){
5048 var r = [], ri = -1;
5049 tagName = tagName.toLowerCase();
5050 for(var i = 0, ci; ci = cs[i]; i++){
5051 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5058 function byId(cs, attr, id){
5059 if(cs.tagName || cs == document){
5065 var r = [], ri = -1;
5066 for(var i = 0,ci; ci = cs[i]; i++){
5067 if(ci && ci.id == id){
5075 function byAttribute(cs, attr, value, op, custom){
5076 var r = [], ri = -1, st = custom=="{";
5077 var f = Roo.DomQuery.operators[op];
5078 for(var i = 0, ci; ci = cs[i]; i++){
5081 a = Roo.DomQuery.getStyle(ci, attr);
5083 else if(attr == "class" || attr == "className"){
5085 }else if(attr == "for"){
5087 }else if(attr == "href"){
5088 a = ci.getAttribute("href", 2);
5090 a = ci.getAttribute(attr);
5092 if((f && f(a, value)) || (!f && a)){
5099 function byPseudo(cs, name, value){
5100 return Roo.DomQuery.pseudos[name](cs, value);
5103 // This is for IE MSXML which does not support expandos.
5104 // IE runs the same speed using setAttribute, however FF slows way down
5105 // and Safari completely fails so they need to continue to use expandos.
5106 var isIE = window.ActiveXObject ? true : false;
5108 // this eval is stop the compressor from
5109 // renaming the variable to something shorter
5111 /** eval:var:batch */
5116 function nodupIEXml(cs){
5118 cs[0].setAttribute("_nodup", d);
5120 for(var i = 1, len = cs.length; i < len; i++){
5122 if(!c.getAttribute("_nodup") != d){
5123 c.setAttribute("_nodup", d);
5127 for(var i = 0, len = cs.length; i < len; i++){
5128 cs[i].removeAttribute("_nodup");
5137 var len = cs.length, c, i, r = cs, cj, ri = -1;
5138 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5141 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5142 return nodupIEXml(cs);
5146 for(i = 1; c = cs[i]; i++){
5151 for(var j = 0; j < i; j++){
5154 for(j = i+1; cj = cs[j]; j++){
5166 function quickDiffIEXml(c1, c2){
5168 for(var i = 0, len = c1.length; i < len; i++){
5169 c1[i].setAttribute("_qdiff", d);
5172 for(var i = 0, len = c2.length; i < len; i++){
5173 if(c2[i].getAttribute("_qdiff") != d){
5174 r[r.length] = c2[i];
5177 for(var i = 0, len = c1.length; i < len; i++){
5178 c1[i].removeAttribute("_qdiff");
5183 function quickDiff(c1, c2){
5184 var len1 = c1.length;
5188 if(isIE && c1[0].selectSingleNode){
5189 return quickDiffIEXml(c1, c2);
5192 for(var i = 0; i < len1; i++){
5196 for(var i = 0, len = c2.length; i < len; i++){
5197 if(c2[i]._qdiff != d){
5198 r[r.length] = c2[i];
5204 function quickId(ns, mode, root, id){
5206 var d = root.ownerDocument || root;
5207 return d.getElementById(id);
5209 ns = getNodes(ns, mode, "*");
5210 return byId(ns, null, id);
5214 getStyle : function(el, name){
5215 return Roo.fly(el).getStyle(name);
5218 * Compiles a selector/xpath query into a reusable function. The returned function
5219 * takes one parameter "root" (optional), which is the context node from where the query should start.
5220 * @param {String} selector The selector/xpath query
5221 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5222 * @return {Function}
5224 compile : function(path, type){
5225 type = type || "select";
5227 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5228 var q = path, mode, lq;
5229 var tk = Roo.DomQuery.matchers;
5230 var tklen = tk.length;
5233 // accept leading mode switch
5234 var lmode = q.match(modeRe);
5235 if(lmode && lmode[1]){
5236 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5237 q = q.replace(lmode[1], "");
5239 // strip leading slashes
5240 while(path.substr(0, 1)=="/"){
5241 path = path.substr(1);
5244 while(q && lq != q){
5246 var tm = q.match(tagTokenRe);
5247 if(type == "select"){
5250 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5252 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5254 q = q.replace(tm[0], "");
5255 }else if(q.substr(0, 1) != '@'){
5256 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5261 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5263 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5265 q = q.replace(tm[0], "");
5268 while(!(mm = q.match(modeRe))){
5269 var matched = false;
5270 for(var j = 0; j < tklen; j++){
5272 var m = q.match(t.re);
5274 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5277 q = q.replace(m[0], "");
5282 // prevent infinite loop on bad selector
5284 throw 'Error parsing selector, parsing failed at "' + q + '"';
5288 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5289 q = q.replace(mm[1], "");
5292 fn[fn.length] = "return nodup(n);\n}";
5295 * list of variables that need from compression as they are used by eval.
5305 * eval:var:byClassName
5307 * eval:var:byAttribute
5308 * eval:var:attrValue
5316 * Selects a group of elements.
5317 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5318 * @param {Node} root (optional) The start of the query (defaults to document).
5321 select : function(path, root, type){
5322 if(!root || root == document){
5325 if(typeof root == "string"){
5326 root = document.getElementById(root);
5328 var paths = path.split(",");
5330 for(var i = 0, len = paths.length; i < len; i++){
5331 var p = paths[i].replace(trimRe, "");
5333 cache[p] = Roo.DomQuery.compile(p);
5335 throw p + " is not a valid selector";
5338 var result = cache[p](root);
5339 if(result && result != document){
5340 results = results.concat(result);
5343 if(paths.length > 1){
5344 return nodup(results);
5350 * Selects a single element.
5351 * @param {String} selector The selector/xpath query
5352 * @param {Node} root (optional) The start of the query (defaults to document).
5355 selectNode : function(path, root){
5356 return Roo.DomQuery.select(path, root)[0];
5360 * Selects the value of a node, optionally replacing null with the defaultValue.
5361 * @param {String} selector The selector/xpath query
5362 * @param {Node} root (optional) The start of the query (defaults to document).
5363 * @param {String} defaultValue
5365 selectValue : function(path, root, defaultValue){
5366 path = path.replace(trimRe, "");
5367 if(!valueCache[path]){
5368 valueCache[path] = Roo.DomQuery.compile(path, "select");
5370 var n = valueCache[path](root);
5371 n = n[0] ? n[0] : n;
5372 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5373 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5377 * Selects the value of a node, parsing integers and floats.
5378 * @param {String} selector The selector/xpath query
5379 * @param {Node} root (optional) The start of the query (defaults to document).
5380 * @param {Number} defaultValue
5383 selectNumber : function(path, root, defaultValue){
5384 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5385 return parseFloat(v);
5389 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5390 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5391 * @param {String} selector The simple selector to test
5394 is : function(el, ss){
5395 if(typeof el == "string"){
5396 el = document.getElementById(el);
5398 var isArray = (el instanceof Array);
5399 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5400 return isArray ? (result.length == el.length) : (result.length > 0);
5404 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5405 * @param {Array} el An array of elements to filter
5406 * @param {String} selector The simple selector to test
5407 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5408 * the selector instead of the ones that match
5411 filter : function(els, ss, nonMatches){
5412 ss = ss.replace(trimRe, "");
5413 if(!simpleCache[ss]){
5414 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5416 var result = simpleCache[ss](els);
5417 return nonMatches ? quickDiff(result, els) : result;
5421 * Collection of matching regular expressions and code snippets.
5425 select: 'n = byClassName(n, null, " {1} ");'
5427 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5428 select: 'n = byPseudo(n, "{1}", "{2}");'
5430 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5431 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5434 select: 'n = byId(n, null, "{1}");'
5437 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5442 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5443 * 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, > <.
5446 "=" : function(a, v){
5449 "!=" : function(a, v){
5452 "^=" : function(a, v){
5453 return a && a.substr(0, v.length) == v;
5455 "$=" : function(a, v){
5456 return a && a.substr(a.length-v.length) == v;
5458 "*=" : function(a, v){
5459 return a && a.indexOf(v) !== -1;
5461 "%=" : function(a, v){
5462 return (a % v) == 0;
5464 "|=" : function(a, v){
5465 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5467 "~=" : function(a, v){
5468 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5473 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5474 * and the argument (if any) supplied in the selector.
5477 "first-child" : function(c){
5478 var r = [], ri = -1, n;
5479 for(var i = 0, ci; ci = n = c[i]; i++){
5480 while((n = n.previousSibling) && n.nodeType != 1);
5488 "last-child" : function(c){
5489 var r = [], ri = -1, n;
5490 for(var i = 0, ci; ci = n = c[i]; i++){
5491 while((n = n.nextSibling) && n.nodeType != 1);
5499 "nth-child" : function(c, a) {
5500 var r = [], ri = -1;
5501 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5502 var f = (m[1] || 1) - 0, l = m[2] - 0;
5503 for(var i = 0, n; n = c[i]; i++){
5504 var pn = n.parentNode;
5505 if (batch != pn._batch) {
5507 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5508 if(cn.nodeType == 1){
5515 if (l == 0 || n.nodeIndex == l){
5518 } else if ((n.nodeIndex + l) % f == 0){
5526 "only-child" : function(c){
5527 var r = [], ri = -1;;
5528 for(var i = 0, ci; ci = c[i]; i++){
5529 if(!prev(ci) && !next(ci)){
5536 "empty" : function(c){
5537 var r = [], ri = -1;
5538 for(var i = 0, ci; ci = c[i]; i++){
5539 var cns = ci.childNodes, j = 0, cn, empty = true;
5542 if(cn.nodeType == 1 || cn.nodeType == 3){
5554 "contains" : function(c, v){
5555 var r = [], ri = -1;
5556 for(var i = 0, ci; ci = c[i]; i++){
5557 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5564 "nodeValue" : function(c, v){
5565 var r = [], ri = -1;
5566 for(var i = 0, ci; ci = c[i]; i++){
5567 if(ci.firstChild && ci.firstChild.nodeValue == v){
5574 "checked" : function(c){
5575 var r = [], ri = -1;
5576 for(var i = 0, ci; ci = c[i]; i++){
5577 if(ci.checked == true){
5584 "not" : function(c, ss){
5585 return Roo.DomQuery.filter(c, ss, true);
5588 "odd" : function(c){
5589 return this["nth-child"](c, "odd");
5592 "even" : function(c){
5593 return this["nth-child"](c, "even");
5596 "nth" : function(c, a){
5597 return c[a-1] || [];
5600 "first" : function(c){
5604 "last" : function(c){
5605 return c[c.length-1] || [];
5608 "has" : function(c, ss){
5609 var s = Roo.DomQuery.select;
5610 var r = [], ri = -1;
5611 for(var i = 0, ci; ci = c[i]; i++){
5612 if(s(ss, ci).length > 0){
5619 "next" : function(c, ss){
5620 var is = Roo.DomQuery.is;
5621 var r = [], ri = -1;
5622 for(var i = 0, ci; ci = c[i]; i++){
5631 "prev" : function(c, ss){
5632 var is = Roo.DomQuery.is;
5633 var r = [], ri = -1;
5634 for(var i = 0, ci; ci = c[i]; i++){
5647 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5648 * @param {String} path The selector/xpath query
5649 * @param {Node} root (optional) The start of the query (defaults to document).
5654 Roo.query = Roo.DomQuery.select;
5657 * Ext JS Library 1.1.1
5658 * Copyright(c) 2006-2007, Ext JS, LLC.
5660 * Originally Released Under LGPL - original licence link has changed is not relivant.
5663 * <script type="text/javascript">
5667 * @class Roo.util.Observable
5668 * Base class that provides a common interface for publishing events. Subclasses are expected to
5669 * to have a property "events" with all the events defined.<br>
5672 Employee = function(name){
5679 Roo.extend(Employee, Roo.util.Observable);
5681 * @param {Object} config properties to use (incuding events / listeners)
5684 Roo.util.Observable = function(cfg){
5687 this.addEvents(cfg.events || {});
5689 delete cfg.events; // make sure
5692 Roo.apply(this, cfg);
5695 this.on(this.listeners);
5696 delete this.listeners;
5699 Roo.util.Observable.prototype = {
5701 * @cfg {Object} listeners list of events and functions to call for this object,
5705 'click' : function(e) {
5715 * Fires the specified event with the passed parameters (minus the event name).
5716 * @param {String} eventName
5717 * @param {Object...} args Variable number of parameters are passed to handlers
5718 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5720 fireEvent : function(){
5721 var ce = this.events[arguments[0].toLowerCase()];
5722 if(typeof ce == "object"){
5723 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5730 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5733 * Appends an event handler to this component
5734 * @param {String} eventName The type of event to listen for
5735 * @param {Function} handler The method the event invokes
5736 * @param {Object} scope (optional) The scope in which to execute the handler
5737 * function. The handler function's "this" context.
5738 * @param {Object} options (optional) An object containing handler configuration
5739 * properties. This may contain any of the following properties:<ul>
5740 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5741 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5742 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5743 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5744 * by the specified number of milliseconds. If the event fires again within that time, the original
5745 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5748 * <b>Combining Options</b><br>
5749 * Using the options argument, it is possible to combine different types of listeners:<br>
5751 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5753 el.on('click', this.onClick, this, {
5760 * <b>Attaching multiple handlers in 1 call</b><br>
5761 * The method also allows for a single argument to be passed which is a config object containing properties
5762 * which specify multiple handlers.
5771 fn: this.onMouseOver,
5775 fn: this.onMouseOut,
5781 * Or a shorthand syntax which passes the same scope object to all handlers:
5784 'click': this.onClick,
5785 'mouseover': this.onMouseOver,
5786 'mouseout': this.onMouseOut,
5791 addListener : function(eventName, fn, scope, o){
5792 if(typeof eventName == "object"){
5795 if(this.filterOptRe.test(e)){
5798 if(typeof o[e] == "function"){
5800 this.addListener(e, o[e], o.scope, o);
5802 // individual options
5803 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5808 o = (!o || typeof o == "boolean") ? {} : o;
5809 eventName = eventName.toLowerCase();
5810 var ce = this.events[eventName] || true;
5811 if(typeof ce == "boolean"){
5812 ce = new Roo.util.Event(this, eventName);
5813 this.events[eventName] = ce;
5815 ce.addListener(fn, scope, o);
5819 * Removes a listener
5820 * @param {String} eventName The type of event to listen for
5821 * @param {Function} handler The handler to remove
5822 * @param {Object} scope (optional) The scope (this object) for the handler
5824 removeListener : function(eventName, fn, scope){
5825 var ce = this.events[eventName.toLowerCase()];
5826 if(typeof ce == "object"){
5827 ce.removeListener(fn, scope);
5832 * Removes all listeners for this object
5834 purgeListeners : function(){
5835 for(var evt in this.events){
5836 if(typeof this.events[evt] == "object"){
5837 this.events[evt].clearListeners();
5842 relayEvents : function(o, events){
5843 var createHandler = function(ename){
5845 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5848 for(var i = 0, len = events.length; i < len; i++){
5849 var ename = events[i];
5850 if(!this.events[ename]){ this.events[ename] = true; };
5851 o.on(ename, createHandler(ename), this);
5856 * Used to define events on this Observable
5857 * @param {Object} object The object with the events defined
5859 addEvents : function(o){
5863 Roo.applyIf(this.events, o);
5867 * Checks to see if this object has any listeners for a specified event
5868 * @param {String} eventName The name of the event to check for
5869 * @return {Boolean} True if the event is being listened for, else false
5871 hasListener : function(eventName){
5872 var e = this.events[eventName];
5873 return typeof e == "object" && e.listeners.length > 0;
5877 * Appends an event handler to this element (shorthand for addListener)
5878 * @param {String} eventName The type of event to listen for
5879 * @param {Function} handler The method the event invokes
5880 * @param {Object} scope (optional) The scope in which to execute the handler
5881 * function. The handler function's "this" context.
5882 * @param {Object} options (optional)
5885 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5887 * Removes a listener (shorthand for removeListener)
5888 * @param {String} eventName The type of event to listen for
5889 * @param {Function} handler The handler to remove
5890 * @param {Object} scope (optional) The scope (this object) for the handler
5893 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5896 * Starts capture on the specified Observable. All events will be passed
5897 * to the supplied function with the event name + standard signature of the event
5898 * <b>before</b> the event is fired. If the supplied function returns false,
5899 * the event will not fire.
5900 * @param {Observable} o The Observable to capture
5901 * @param {Function} fn The function to call
5902 * @param {Object} scope (optional) The scope (this object) for the fn
5905 Roo.util.Observable.capture = function(o, fn, scope){
5906 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5910 * Removes <b>all</b> added captures from the Observable.
5911 * @param {Observable} o The Observable to release
5914 Roo.util.Observable.releaseCapture = function(o){
5915 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5920 var createBuffered = function(h, o, scope){
5921 var task = new Roo.util.DelayedTask();
5923 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5927 var createSingle = function(h, e, fn, scope){
5929 e.removeListener(fn, scope);
5930 return h.apply(scope, arguments);
5934 var createDelayed = function(h, o, scope){
5936 var args = Array.prototype.slice.call(arguments, 0);
5937 setTimeout(function(){
5938 h.apply(scope, args);
5943 Roo.util.Event = function(obj, name){
5946 this.listeners = [];
5949 Roo.util.Event.prototype = {
5950 addListener : function(fn, scope, options){
5951 var o = options || {};
5952 scope = scope || this.obj;
5953 if(!this.isListening(fn, scope)){
5954 var l = {fn: fn, scope: scope, options: o};
5957 h = createDelayed(h, o, scope);
5960 h = createSingle(h, this, fn, scope);
5963 h = createBuffered(h, o, scope);
5966 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5967 this.listeners.push(l);
5969 this.listeners = this.listeners.slice(0);
5970 this.listeners.push(l);
5975 findListener : function(fn, scope){
5976 scope = scope || this.obj;
5977 var ls = this.listeners;
5978 for(var i = 0, len = ls.length; i < len; i++){
5980 if(l.fn == fn && l.scope == scope){
5987 isListening : function(fn, scope){
5988 return this.findListener(fn, scope) != -1;
5991 removeListener : function(fn, scope){
5993 if((index = this.findListener(fn, scope)) != -1){
5995 this.listeners.splice(index, 1);
5997 this.listeners = this.listeners.slice(0);
5998 this.listeners.splice(index, 1);
6005 clearListeners : function(){
6006 this.listeners = [];
6010 var ls = this.listeners, scope, len = ls.length;
6013 var args = Array.prototype.slice.call(arguments, 0);
6014 for(var i = 0; i < len; i++){
6016 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6017 this.firing = false;
6021 this.firing = false;
6028 * Ext JS Library 1.1.1
6029 * Copyright(c) 2006-2007, Ext JS, LLC.
6031 * Originally Released Under LGPL - original licence link has changed is not relivant.
6034 * <script type="text/javascript">
6038 * @class Roo.EventManager
6039 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6040 * several useful events directly.
6041 * See {@link Roo.EventObject} for more details on normalized event objects.
6044 Roo.EventManager = function(){
6045 var docReadyEvent, docReadyProcId, docReadyState = false;
6046 var resizeEvent, resizeTask, textEvent, textSize;
6047 var E = Roo.lib.Event;
6048 var D = Roo.lib.Dom;
6051 var fireDocReady = function(){
6053 docReadyState = true;
6056 clearInterval(docReadyProcId);
6058 if(Roo.isGecko || Roo.isOpera) {
6059 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6062 var defer = document.getElementById("ie-deferred-loader");
6064 defer.onreadystatechange = null;
6065 defer.parentNode.removeChild(defer);
6069 docReadyEvent.fire();
6070 docReadyEvent.clearListeners();
6075 var initDocReady = function(){
6076 docReadyEvent = new Roo.util.Event();
6077 if(Roo.isGecko || Roo.isOpera) {
6078 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6080 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6081 var defer = document.getElementById("ie-deferred-loader");
6082 defer.onreadystatechange = function(){
6083 if(this.readyState == "complete"){
6087 }else if(Roo.isSafari){
6088 docReadyProcId = setInterval(function(){
6089 var rs = document.readyState;
6090 if(rs == "complete") {
6095 // no matter what, make sure it fires on load
6096 E.on(window, "load", fireDocReady);
6099 var createBuffered = function(h, o){
6100 var task = new Roo.util.DelayedTask(h);
6102 // create new event object impl so new events don't wipe out properties
6103 e = new Roo.EventObjectImpl(e);
6104 task.delay(o.buffer, h, null, [e]);
6108 var createSingle = function(h, el, ename, fn){
6110 Roo.EventManager.removeListener(el, ename, fn);
6115 var createDelayed = function(h, o){
6117 // create new event object impl so new events don't wipe out properties
6118 e = new Roo.EventObjectImpl(e);
6119 setTimeout(function(){
6125 var listen = function(element, ename, opt, fn, scope){
6126 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6127 fn = fn || o.fn; scope = scope || o.scope;
6128 var el = Roo.getDom(element);
6130 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6132 var h = function(e){
6133 e = Roo.EventObject.setEvent(e);
6136 t = e.getTarget(o.delegate, el);
6143 if(o.stopEvent === true){
6146 if(o.preventDefault === true){
6149 if(o.stopPropagation === true){
6150 e.stopPropagation();
6153 if(o.normalized === false){
6157 fn.call(scope || el, e, t, o);
6160 h = createDelayed(h, o);
6163 h = createSingle(h, el, ename, fn);
6166 h = createBuffered(h, o);
6168 fn._handlers = fn._handlers || [];
6169 fn._handlers.push([Roo.id(el), ename, h]);
6172 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6173 el.addEventListener("DOMMouseScroll", h, false);
6174 E.on(window, 'unload', function(){
6175 el.removeEventListener("DOMMouseScroll", h, false);
6178 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6179 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6184 var stopListening = function(el, ename, fn){
6185 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6187 for(var i = 0, len = hds.length; i < len; i++){
6189 if(h[0] == id && h[1] == ename){
6196 E.un(el, ename, hd);
6197 el = Roo.getDom(el);
6198 if(ename == "mousewheel" && el.addEventListener){
6199 el.removeEventListener("DOMMouseScroll", hd, false);
6201 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6202 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6206 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6213 * @scope Roo.EventManager
6218 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6219 * object with a Roo.EventObject
6220 * @param {Function} fn The method the event invokes
6221 * @param {Object} scope An object that becomes the scope of the handler
6222 * @param {boolean} override If true, the obj passed in becomes
6223 * the execution scope of the listener
6224 * @return {Function} The wrapped function
6227 wrap : function(fn, scope, override){
6229 Roo.EventObject.setEvent(e);
6230 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6235 * Appends an event handler to an element (shorthand for addListener)
6236 * @param {String/HTMLElement} element The html element or id to assign the
6237 * @param {String} eventName The type of event to listen for
6238 * @param {Function} handler The method the event invokes
6239 * @param {Object} scope (optional) The scope in which to execute the handler
6240 * function. The handler function's "this" context.
6241 * @param {Object} options (optional) An object containing handler configuration
6242 * properties. This may contain any of the following properties:<ul>
6243 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6244 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6245 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6246 * <li>preventDefault {Boolean} True to prevent the default action</li>
6247 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6248 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6249 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6250 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6251 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6252 * by the specified number of milliseconds. If the event fires again within that time, the original
6253 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6256 * <b>Combining Options</b><br>
6257 * Using the options argument, it is possible to combine different types of listeners:<br>
6259 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6261 el.on('click', this.onClick, this, {
6268 * <b>Attaching multiple handlers in 1 call</b><br>
6269 * The method also allows for a single argument to be passed which is a config object containing properties
6270 * which specify multiple handlers.
6280 fn: this.onMouseOver
6289 * Or a shorthand syntax:<br>
6292 'click' : this.onClick,
6293 'mouseover' : this.onMouseOver,
6294 'mouseout' : this.onMouseOut
6298 addListener : function(element, eventName, fn, scope, options){
6299 if(typeof eventName == "object"){
6305 if(typeof o[e] == "function"){
6307 listen(element, e, o, o[e], o.scope);
6309 // individual options
6310 listen(element, e, o[e]);
6315 return listen(element, eventName, options, fn, scope);
6319 * Removes an event handler
6321 * @param {String/HTMLElement} element The id or html element to remove the
6323 * @param {String} eventName The type of event
6324 * @param {Function} fn
6325 * @return {Boolean} True if a listener was actually removed
6327 removeListener : function(element, eventName, fn){
6328 return stopListening(element, eventName, fn);
6332 * Fires when the document is ready (before onload and before images are loaded). Can be
6333 * accessed shorthanded Roo.onReady().
6334 * @param {Function} fn The method the event invokes
6335 * @param {Object} scope An object that becomes the scope of the handler
6336 * @param {boolean} options
6338 onDocumentReady : function(fn, scope, options){
6339 if(docReadyState){ // if it already fired
6340 docReadyEvent.addListener(fn, scope, options);
6341 docReadyEvent.fire();
6342 docReadyEvent.clearListeners();
6348 docReadyEvent.addListener(fn, scope, options);
6352 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6353 * @param {Function} fn The method the event invokes
6354 * @param {Object} scope An object that becomes the scope of the handler
6355 * @param {boolean} options
6357 onWindowResize : function(fn, scope, options){
6359 resizeEvent = new Roo.util.Event();
6360 resizeTask = new Roo.util.DelayedTask(function(){
6361 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6363 E.on(window, "resize", function(){
6365 resizeTask.delay(50);
6367 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6371 resizeEvent.addListener(fn, scope, options);
6375 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6376 * @param {Function} fn The method the event invokes
6377 * @param {Object} scope An object that becomes the scope of the handler
6378 * @param {boolean} options
6380 onTextResize : function(fn, scope, options){
6382 textEvent = new Roo.util.Event();
6383 var textEl = new Roo.Element(document.createElement('div'));
6384 textEl.dom.className = 'x-text-resize';
6385 textEl.dom.innerHTML = 'X';
6386 textEl.appendTo(document.body);
6387 textSize = textEl.dom.offsetHeight;
6388 setInterval(function(){
6389 if(textEl.dom.offsetHeight != textSize){
6390 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6392 }, this.textResizeInterval);
6394 textEvent.addListener(fn, scope, options);
6398 * Removes the passed window resize listener.
6399 * @param {Function} fn The method the event invokes
6400 * @param {Object} scope The scope of handler
6402 removeResizeListener : function(fn, scope){
6404 resizeEvent.removeListener(fn, scope);
6409 fireResize : function(){
6411 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6415 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6419 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6421 textResizeInterval : 50
6426 * @scopeAlias pub=Roo.EventManager
6430 * Appends an event handler to an element (shorthand for addListener)
6431 * @param {String/HTMLElement} element The html element or id to assign the
6432 * @param {String} eventName The type of event to listen for
6433 * @param {Function} handler The method the event invokes
6434 * @param {Object} scope (optional) The scope in which to execute the handler
6435 * function. The handler function's "this" context.
6436 * @param {Object} options (optional) An object containing handler configuration
6437 * properties. This may contain any of the following properties:<ul>
6438 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6439 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6440 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6441 * <li>preventDefault {Boolean} True to prevent the default action</li>
6442 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6443 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6444 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6445 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6446 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6447 * by the specified number of milliseconds. If the event fires again within that time, the original
6448 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6451 * <b>Combining Options</b><br>
6452 * Using the options argument, it is possible to combine different types of listeners:<br>
6454 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6456 el.on('click', this.onClick, this, {
6463 * <b>Attaching multiple handlers in 1 call</b><br>
6464 * The method also allows for a single argument to be passed which is a config object containing properties
6465 * which specify multiple handlers.
6475 fn: this.onMouseOver
6484 * Or a shorthand syntax:<br>
6487 'click' : this.onClick,
6488 'mouseover' : this.onMouseOver,
6489 'mouseout' : this.onMouseOut
6493 pub.on = pub.addListener;
6494 pub.un = pub.removeListener;
6496 pub.stoppedMouseDownEvent = new Roo.util.Event();
6500 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6501 * @param {Function} fn The method the event invokes
6502 * @param {Object} scope An object that becomes the scope of the handler
6503 * @param {boolean} override If true, the obj passed in becomes
6504 * the execution scope of the listener
6508 Roo.onReady = Roo.EventManager.onDocumentReady;
6510 Roo.onReady(function(){
6511 var bd = Roo.get(document.body);
6516 : Roo.isGecko ? "roo-gecko"
6517 : Roo.isOpera ? "roo-opera"
6518 : Roo.isSafari ? "roo-safari" : ""];
6521 cls.push("roo-mac");
6524 cls.push("roo-linux");
6526 if(Roo.isBorderBox){
6527 cls.push('roo-border-box');
6529 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6530 var p = bd.dom.parentNode;
6532 p.className += ' roo-strict';
6535 bd.addClass(cls.join(' '));
6539 * @class Roo.EventObject
6540 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6541 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6544 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6546 var target = e.getTarget();
6549 var myDiv = Roo.get("myDiv");
6550 myDiv.on("click", handleClick);
6552 Roo.EventManager.on("myDiv", 'click', handleClick);
6553 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6557 Roo.EventObject = function(){
6559 var E = Roo.lib.Event;
6561 // safari keypress events for special keys return bad keycodes
6564 63235 : 39, // right
6567 63276 : 33, // page up
6568 63277 : 34, // page down
6569 63272 : 46, // delete
6574 // normalize button clicks
6575 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6576 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6578 Roo.EventObjectImpl = function(e){
6580 this.setEvent(e.browserEvent || e);
6583 Roo.EventObjectImpl.prototype = {
6585 * Used to fix doc tools.
6586 * @scope Roo.EventObject.prototype
6592 /** The normal browser event */
6593 browserEvent : null,
6594 /** The button pressed in a mouse event */
6596 /** True if the shift key was down during the event */
6598 /** True if the control key was down during the event */
6600 /** True if the alt key was down during the event */
6659 setEvent : function(e){
6660 if(e == this || (e && e.browserEvent)){ // already wrapped
6663 this.browserEvent = e;
6665 // normalize buttons
6666 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6667 if(e.type == 'click' && this.button == -1){
6671 this.shiftKey = e.shiftKey;
6672 // mac metaKey behaves like ctrlKey
6673 this.ctrlKey = e.ctrlKey || e.metaKey;
6674 this.altKey = e.altKey;
6675 // in getKey these will be normalized for the mac
6676 this.keyCode = e.keyCode;
6677 // keyup warnings on firefox.
6678 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6679 // cache the target for the delayed and or buffered events
6680 this.target = E.getTarget(e);
6682 this.xy = E.getXY(e);
6685 this.shiftKey = false;
6686 this.ctrlKey = false;
6687 this.altKey = false;
6697 * Stop the event (preventDefault and stopPropagation)
6699 stopEvent : function(){
6700 if(this.browserEvent){
6701 if(this.browserEvent.type == 'mousedown'){
6702 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6704 E.stopEvent(this.browserEvent);
6709 * Prevents the browsers default handling of the event.
6711 preventDefault : function(){
6712 if(this.browserEvent){
6713 E.preventDefault(this.browserEvent);
6718 isNavKeyPress : function(){
6719 var k = this.keyCode;
6720 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6721 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6724 isSpecialKey : function(){
6725 var k = this.keyCode;
6726 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6727 (k == 16) || (k == 17) ||
6728 (k >= 18 && k <= 20) ||
6729 (k >= 33 && k <= 35) ||
6730 (k >= 36 && k <= 39) ||
6731 (k >= 44 && k <= 45);
6734 * Cancels bubbling of the event.
6736 stopPropagation : function(){
6737 if(this.browserEvent){
6738 if(this.type == 'mousedown'){
6739 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6741 E.stopPropagation(this.browserEvent);
6746 * Gets the key code for the event.
6749 getCharCode : function(){
6750 return this.charCode || this.keyCode;
6754 * Returns a normalized keyCode for the event.
6755 * @return {Number} The key code
6757 getKey : function(){
6758 var k = this.keyCode || this.charCode;
6759 return Roo.isSafari ? (safariKeys[k] || k) : k;
6763 * Gets the x coordinate of the event.
6766 getPageX : function(){
6771 * Gets the y coordinate of the event.
6774 getPageY : function(){
6779 * Gets the time of the event.
6782 getTime : function(){
6783 if(this.browserEvent){
6784 return E.getTime(this.browserEvent);
6790 * Gets the page coordinates of the event.
6791 * @return {Array} The xy values like [x, y]
6798 * Gets the target for the event.
6799 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6800 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6801 search as a number or element (defaults to 10 || document.body)
6802 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6803 * @return {HTMLelement}
6805 getTarget : function(selector, maxDepth, returnEl){
6806 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6809 * Gets the related target.
6810 * @return {HTMLElement}
6812 getRelatedTarget : function(){
6813 if(this.browserEvent){
6814 return E.getRelatedTarget(this.browserEvent);
6820 * Normalizes mouse wheel delta across browsers
6821 * @return {Number} The delta
6823 getWheelDelta : function(){
6824 var e = this.browserEvent;
6826 if(e.wheelDelta){ /* IE/Opera. */
6827 delta = e.wheelDelta/120;
6828 }else if(e.detail){ /* Mozilla case. */
6829 delta = -e.detail/3;
6835 * Returns true if the control, meta, shift or alt key was pressed during this event.
6838 hasModifier : function(){
6839 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6843 * Returns true if the target of this event equals el or is a child of el
6844 * @param {String/HTMLElement/Element} el
6845 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6848 within : function(el, related){
6849 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6850 return t && Roo.fly(el).contains(t);
6853 getPoint : function(){
6854 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6858 return new Roo.EventObjectImpl();
6863 * Ext JS Library 1.1.1
6864 * Copyright(c) 2006-2007, Ext JS, LLC.
6866 * Originally Released Under LGPL - original licence link has changed is not relivant.
6869 * <script type="text/javascript">
6873 // was in Composite Element!??!?!
6876 var D = Roo.lib.Dom;
6877 var E = Roo.lib.Event;
6878 var A = Roo.lib.Anim;
6880 // local style camelizing for speed
6882 var camelRe = /(-[a-z])/gi;
6883 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6884 var view = document.defaultView;
6887 * @class Roo.Element
6888 * Represents an Element in the DOM.<br><br>
6891 var el = Roo.get("my-div");
6894 var el = getEl("my-div");
6896 // or with a DOM element
6897 var el = Roo.get(myDivElement);
6899 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6900 * each call instead of constructing a new one.<br><br>
6901 * <b>Animations</b><br />
6902 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6903 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6905 Option Default Description
6906 --------- -------- ---------------------------------------------
6907 duration .35 The duration of the animation in seconds
6908 easing easeOut The YUI easing method
6909 callback none A function to execute when the anim completes
6910 scope this The scope (this) of the callback function
6912 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6913 * manipulate the animation. Here's an example:
6915 var el = Roo.get("my-div");
6920 // default animation
6921 el.setWidth(100, true);
6923 // animation with some options set
6930 // using the "anim" property to get the Anim object
6936 el.setWidth(100, opt);
6938 if(opt.anim.isAnimated()){
6942 * <b> Composite (Collections of) Elements</b><br />
6943 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6944 * @constructor Create a new Element directly.
6945 * @param {String/HTMLElement} element
6946 * @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).
6948 Roo.Element = function(element, forceNew){
6949 var dom = typeof element == "string" ?
6950 document.getElementById(element) : element;
6951 if(!dom){ // invalid id/element
6955 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6956 return Roo.Element.cache[id];
6966 * The DOM element ID
6969 this.id = id || Roo.id(dom);
6972 var El = Roo.Element;
6976 * The element's default display mode (defaults to "")
6979 originalDisplay : "",
6983 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6988 * Sets the element's visibility mode. When setVisible() is called it
6989 * will use this to determine whether to set the visibility or the display property.
6990 * @param visMode Element.VISIBILITY or Element.DISPLAY
6991 * @return {Roo.Element} this
6993 setVisibilityMode : function(visMode){
6994 this.visibilityMode = visMode;
6998 * Convenience method for setVisibilityMode(Element.DISPLAY)
6999 * @param {String} display (optional) What to set display to when visible
7000 * @return {Roo.Element} this
7002 enableDisplayMode : function(display){
7003 this.setVisibilityMode(El.DISPLAY);
7004 if(typeof display != "undefined") this.originalDisplay = display;
7009 * 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)
7010 * @param {String} selector The simple selector to test
7011 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7012 search as a number or element (defaults to 10 || document.body)
7013 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7014 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7016 findParent : function(simpleSelector, maxDepth, returnEl){
7017 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7018 maxDepth = maxDepth || 50;
7019 if(typeof maxDepth != "number"){
7020 stopEl = Roo.getDom(maxDepth);
7023 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7024 if(dq.is(p, simpleSelector)){
7025 return returnEl ? Roo.get(p) : p;
7035 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7036 * @param {String} selector The simple selector to test
7037 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7038 search as a number or element (defaults to 10 || document.body)
7039 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7040 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7042 findParentNode : function(simpleSelector, maxDepth, returnEl){
7043 var p = Roo.fly(this.dom.parentNode, '_internal');
7044 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7048 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7049 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7050 * @param {String} selector The simple selector to test
7051 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7052 search as a number or element (defaults to 10 || document.body)
7053 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7055 up : function(simpleSelector, maxDepth){
7056 return this.findParentNode(simpleSelector, maxDepth, true);
7062 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7063 * @param {String} selector The simple selector to test
7064 * @return {Boolean} True if this element matches the selector, else false
7066 is : function(simpleSelector){
7067 return Roo.DomQuery.is(this.dom, simpleSelector);
7071 * Perform animation on this element.
7072 * @param {Object} args The YUI animation control args
7073 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7074 * @param {Function} onComplete (optional) Function to call when animation completes
7075 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7076 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7077 * @return {Roo.Element} this
7079 animate : function(args, duration, onComplete, easing, animType){
7080 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7085 * @private Internal animation call
7087 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7088 animType = animType || 'run';
7090 var anim = Roo.lib.Anim[animType](
7092 (opt.duration || defaultDur) || .35,
7093 (opt.easing || defaultEase) || 'easeOut',
7095 Roo.callback(cb, this);
7096 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7104 // private legacy anim prep
7105 preanim : function(a, i){
7106 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7110 * Removes worthless text nodes
7111 * @param {Boolean} forceReclean (optional) By default the element
7112 * keeps track if it has been cleaned already so
7113 * you can call this over and over. However, if you update the element and
7114 * need to force a reclean, you can pass true.
7116 clean : function(forceReclean){
7117 if(this.isCleaned && forceReclean !== true){
7121 var d = this.dom, n = d.firstChild, ni = -1;
7123 var nx = n.nextSibling;
7124 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7131 this.isCleaned = true;
7136 calcOffsetsTo : function(el){
7139 var restorePos = false;
7140 if(el.getStyle('position') == 'static'){
7141 el.position('relative');
7146 while(op && op != d && op.tagName != 'HTML'){
7149 op = op.offsetParent;
7152 el.position('static');
7158 * Scrolls this element into view within the passed container.
7159 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7160 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7161 * @return {Roo.Element} this
7163 scrollIntoView : function(container, hscroll){
7164 var c = Roo.getDom(container) || document.body;
7167 var o = this.calcOffsetsTo(c),
7170 b = t+el.offsetHeight,
7171 r = l+el.offsetWidth;
7173 var ch = c.clientHeight;
7174 var ct = parseInt(c.scrollTop, 10);
7175 var cl = parseInt(c.scrollLeft, 10);
7177 var cr = cl + c.clientWidth;
7185 if(hscroll !== false){
7189 c.scrollLeft = r-c.clientWidth;
7196 scrollChildIntoView : function(child, hscroll){
7197 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7201 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7202 * the new height may not be available immediately.
7203 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7204 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7205 * @param {Function} onComplete (optional) Function to call when animation completes
7206 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7207 * @return {Roo.Element} this
7209 autoHeight : function(animate, duration, onComplete, easing){
7210 var oldHeight = this.getHeight();
7212 this.setHeight(1); // force clipping
7213 setTimeout(function(){
7214 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7216 this.setHeight(height);
7218 if(typeof onComplete == "function"){
7222 this.setHeight(oldHeight); // restore original height
7223 this.setHeight(height, animate, duration, function(){
7225 if(typeof onComplete == "function") onComplete();
7226 }.createDelegate(this), easing);
7228 }.createDelegate(this), 0);
7233 * Returns true if this element is an ancestor of the passed element
7234 * @param {HTMLElement/String} el The element to check
7235 * @return {Boolean} True if this element is an ancestor of el, else false
7237 contains : function(el){
7238 if(!el){return false;}
7239 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7243 * Checks whether the element is currently visible using both visibility and display properties.
7244 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7245 * @return {Boolean} True if the element is currently visible, else false
7247 isVisible : function(deep) {
7248 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7249 if(deep !== true || !vis){
7252 var p = this.dom.parentNode;
7253 while(p && p.tagName.toLowerCase() != "body"){
7254 if(!Roo.fly(p, '_isVisible').isVisible()){
7263 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7264 * @param {String} selector The CSS selector
7265 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7266 * @return {CompositeElement/CompositeElementLite} The composite element
7268 select : function(selector, unique){
7269 return El.select(selector, unique, this.dom);
7273 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7274 * @param {String} selector The CSS selector
7275 * @return {Array} An array of the matched nodes
7277 query : function(selector, unique){
7278 return Roo.DomQuery.select(selector, this.dom);
7282 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7283 * @param {String} selector The CSS selector
7284 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7285 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7287 child : function(selector, returnDom){
7288 var n = Roo.DomQuery.selectNode(selector, this.dom);
7289 return returnDom ? n : Roo.get(n);
7293 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7294 * @param {String} selector The CSS selector
7295 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7296 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7298 down : function(selector, returnDom){
7299 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7300 return returnDom ? n : Roo.get(n);
7304 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7305 * @param {String} group The group the DD object is member of
7306 * @param {Object} config The DD config object
7307 * @param {Object} overrides An object containing methods to override/implement on the DD object
7308 * @return {Roo.dd.DD} The DD object
7310 initDD : function(group, config, overrides){
7311 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7312 return Roo.apply(dd, overrides);
7316 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7317 * @param {String} group The group the DDProxy object is member of
7318 * @param {Object} config The DDProxy config object
7319 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7320 * @return {Roo.dd.DDProxy} The DDProxy object
7322 initDDProxy : function(group, config, overrides){
7323 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7324 return Roo.apply(dd, overrides);
7328 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7329 * @param {String} group The group the DDTarget object is member of
7330 * @param {Object} config The DDTarget config object
7331 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7332 * @return {Roo.dd.DDTarget} The DDTarget object
7334 initDDTarget : function(group, config, overrides){
7335 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7336 return Roo.apply(dd, overrides);
7340 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7341 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7342 * @param {Boolean} visible Whether the element is visible
7343 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7344 * @return {Roo.Element} this
7346 setVisible : function(visible, animate){
7348 if(this.visibilityMode == El.DISPLAY){
7349 this.setDisplayed(visible);
7352 this.dom.style.visibility = visible ? "visible" : "hidden";
7355 // closure for composites
7357 var visMode = this.visibilityMode;
7359 this.setOpacity(.01);
7360 this.setVisible(true);
7362 this.anim({opacity: { to: (visible?1:0) }},
7363 this.preanim(arguments, 1),
7364 null, .35, 'easeIn', function(){
7366 if(visMode == El.DISPLAY){
7367 dom.style.display = "none";
7369 dom.style.visibility = "hidden";
7371 Roo.get(dom).setOpacity(1);
7379 * Returns true if display is not "none"
7382 isDisplayed : function() {
7383 return this.getStyle("display") != "none";
7387 * Toggles the element's visibility or display, depending on visibility mode.
7388 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7389 * @return {Roo.Element} this
7391 toggle : function(animate){
7392 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7397 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7398 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7399 * @return {Roo.Element} this
7401 setDisplayed : function(value) {
7402 if(typeof value == "boolean"){
7403 value = value ? this.originalDisplay : "none";
7405 this.setStyle("display", value);
7410 * Tries to focus the element. Any exceptions are caught and ignored.
7411 * @return {Roo.Element} this
7413 focus : function() {
7421 * Tries to blur the element. Any exceptions are caught and ignored.
7422 * @return {Roo.Element} this
7432 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7433 * @param {String/Array} className The CSS class to add, or an array of classes
7434 * @return {Roo.Element} this
7436 addClass : function(className){
7437 if(className instanceof Array){
7438 for(var i = 0, len = className.length; i < len; i++) {
7439 this.addClass(className[i]);
7442 if(className && !this.hasClass(className)){
7443 this.dom.className = this.dom.className + " " + className;
7450 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7451 * @param {String/Array} className The CSS class to add, or an array of classes
7452 * @return {Roo.Element} this
7454 radioClass : function(className){
7455 var siblings = this.dom.parentNode.childNodes;
7456 for(var i = 0; i < siblings.length; i++) {
7457 var s = siblings[i];
7458 if(s.nodeType == 1){
7459 Roo.get(s).removeClass(className);
7462 this.addClass(className);
7467 * Removes one or more CSS classes from the element.
7468 * @param {String/Array} className The CSS class to remove, or an array of classes
7469 * @return {Roo.Element} this
7471 removeClass : function(className){
7472 if(!className || !this.dom.className){
7475 if(className instanceof Array){
7476 for(var i = 0, len = className.length; i < len; i++) {
7477 this.removeClass(className[i]);
7480 if(this.hasClass(className)){
7481 var re = this.classReCache[className];
7483 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7484 this.classReCache[className] = re;
7486 this.dom.className =
7487 this.dom.className.replace(re, " ");
7497 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7498 * @param {String} className The CSS class to toggle
7499 * @return {Roo.Element} this
7501 toggleClass : function(className){
7502 if(this.hasClass(className)){
7503 this.removeClass(className);
7505 this.addClass(className);
7511 * Checks if the specified CSS class exists on this element's DOM node.
7512 * @param {String} className The CSS class to check for
7513 * @return {Boolean} True if the class exists, else false
7515 hasClass : function(className){
7516 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7520 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7521 * @param {String} oldClassName The CSS class to replace
7522 * @param {String} newClassName The replacement CSS class
7523 * @return {Roo.Element} this
7525 replaceClass : function(oldClassName, newClassName){
7526 this.removeClass(oldClassName);
7527 this.addClass(newClassName);
7532 * Returns an object with properties matching the styles requested.
7533 * For example, el.getStyles('color', 'font-size', 'width') might return
7534 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7535 * @param {String} style1 A style name
7536 * @param {String} style2 A style name
7537 * @param {String} etc.
7538 * @return {Object} The style object
7540 getStyles : function(){
7541 var a = arguments, len = a.length, r = {};
7542 for(var i = 0; i < len; i++){
7543 r[a[i]] = this.getStyle(a[i]);
7549 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7550 * @param {String} property The style property whose value is returned.
7551 * @return {String} The current value of the style property for this element.
7553 getStyle : function(){
7554 return view && view.getComputedStyle ?
7556 var el = this.dom, v, cs, camel;
7557 if(prop == 'float'){
7560 if(el.style && (v = el.style[prop])){
7563 if(cs = view.getComputedStyle(el, "")){
7564 if(!(camel = propCache[prop])){
7565 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7572 var el = this.dom, v, cs, camel;
7573 if(prop == 'opacity'){
7574 if(typeof el.style.filter == 'string'){
7575 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7577 var fv = parseFloat(m[1]);
7579 return fv ? fv / 100 : 0;
7584 }else if(prop == 'float'){
7585 prop = "styleFloat";
7587 if(!(camel = propCache[prop])){
7588 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7590 if(v = el.style[camel]){
7593 if(cs = el.currentStyle){
7601 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7602 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7603 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7604 * @return {Roo.Element} this
7606 setStyle : function(prop, value){
7607 if(typeof prop == "string"){
7609 if (prop == 'float') {
7610 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7615 if(!(camel = propCache[prop])){
7616 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7619 if(camel == 'opacity') {
7620 this.setOpacity(value);
7622 this.dom.style[camel] = value;
7625 for(var style in prop){
7626 if(typeof prop[style] != "function"){
7627 this.setStyle(style, prop[style]);
7635 * More flexible version of {@link #setStyle} for setting style properties.
7636 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7637 * a function which returns such a specification.
7638 * @return {Roo.Element} this
7640 applyStyles : function(style){
7641 Roo.DomHelper.applyStyles(this.dom, style);
7646 * 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).
7647 * @return {Number} The X position of the element
7650 return D.getX(this.dom);
7654 * 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).
7655 * @return {Number} The Y position of the element
7658 return D.getY(this.dom);
7662 * 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).
7663 * @return {Array} The XY position of the element
7666 return D.getXY(this.dom);
7670 * 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).
7671 * @param {Number} The X position of the element
7672 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7673 * @return {Roo.Element} this
7675 setX : function(x, animate){
7677 D.setX(this.dom, x);
7679 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7685 * 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).
7686 * @param {Number} The Y position of the element
7687 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7688 * @return {Roo.Element} this
7690 setY : function(y, animate){
7692 D.setY(this.dom, y);
7694 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7700 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7701 * @param {String} left The left CSS property value
7702 * @return {Roo.Element} this
7704 setLeft : function(left){
7705 this.setStyle("left", this.addUnits(left));
7710 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7711 * @param {String} top The top CSS property value
7712 * @return {Roo.Element} this
7714 setTop : function(top){
7715 this.setStyle("top", this.addUnits(top));
7720 * Sets the element's CSS right style.
7721 * @param {String} right The right CSS property value
7722 * @return {Roo.Element} this
7724 setRight : function(right){
7725 this.setStyle("right", this.addUnits(right));
7730 * Sets the element's CSS bottom style.
7731 * @param {String} bottom The bottom CSS property value
7732 * @return {Roo.Element} this
7734 setBottom : function(bottom){
7735 this.setStyle("bottom", this.addUnits(bottom));
7740 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7741 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7742 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7743 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7744 * @return {Roo.Element} this
7746 setXY : function(pos, animate){
7748 D.setXY(this.dom, pos);
7750 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7756 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7757 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7758 * @param {Number} x X value for new position (coordinates are page-based)
7759 * @param {Number} y Y value for new position (coordinates are page-based)
7760 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7761 * @return {Roo.Element} this
7763 setLocation : function(x, y, animate){
7764 this.setXY([x, y], this.preanim(arguments, 2));
7769 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7770 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7771 * @param {Number} x X value for new position (coordinates are page-based)
7772 * @param {Number} y Y value for new position (coordinates are page-based)
7773 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7774 * @return {Roo.Element} this
7776 moveTo : function(x, y, animate){
7777 this.setXY([x, y], this.preanim(arguments, 2));
7782 * Returns the region of the given element.
7783 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7784 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7786 getRegion : function(){
7787 return D.getRegion(this.dom);
7791 * Returns the offset height of the element
7792 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7793 * @return {Number} The element's height
7795 getHeight : function(contentHeight){
7796 var h = this.dom.offsetHeight || 0;
7797 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7801 * Returns the offset width of the element
7802 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7803 * @return {Number} The element's width
7805 getWidth : function(contentWidth){
7806 var w = this.dom.offsetWidth || 0;
7807 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7811 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7812 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7813 * if a height has not been set using CSS.
7816 getComputedHeight : function(){
7817 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7819 h = parseInt(this.getStyle('height'), 10) || 0;
7820 if(!this.isBorderBox()){
7821 h += this.getFrameWidth('tb');
7828 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7829 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7830 * if a width has not been set using CSS.
7833 getComputedWidth : function(){
7834 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7836 w = parseInt(this.getStyle('width'), 10) || 0;
7837 if(!this.isBorderBox()){
7838 w += this.getFrameWidth('lr');
7845 * Returns the size of the element.
7846 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7847 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7849 getSize : function(contentSize){
7850 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7854 * Returns the width and height of the viewport.
7855 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7857 getViewSize : function(){
7858 var d = this.dom, doc = document, aw = 0, ah = 0;
7859 if(d == doc || d == doc.body){
7860 return {width : D.getViewWidth(), height: D.getViewHeight()};
7863 width : d.clientWidth,
7864 height: d.clientHeight
7870 * Returns the value of the "value" attribute
7871 * @param {Boolean} asNumber true to parse the value as a number
7872 * @return {String/Number}
7874 getValue : function(asNumber){
7875 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7879 adjustWidth : function(width){
7880 if(typeof width == "number"){
7881 if(this.autoBoxAdjust && !this.isBorderBox()){
7882 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7892 adjustHeight : function(height){
7893 if(typeof height == "number"){
7894 if(this.autoBoxAdjust && !this.isBorderBox()){
7895 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7905 * Set the width of the element
7906 * @param {Number} width The new width
7907 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7908 * @return {Roo.Element} this
7910 setWidth : function(width, animate){
7911 width = this.adjustWidth(width);
7913 this.dom.style.width = this.addUnits(width);
7915 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7921 * Set the height of the element
7922 * @param {Number} height The new height
7923 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7924 * @return {Roo.Element} this
7926 setHeight : function(height, animate){
7927 height = this.adjustHeight(height);
7929 this.dom.style.height = this.addUnits(height);
7931 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7937 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7938 * @param {Number} width The new width
7939 * @param {Number} height The new height
7940 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7941 * @return {Roo.Element} this
7943 setSize : function(width, height, animate){
7944 if(typeof width == "object"){ // in case of object from getSize()
7945 height = width.height; width = width.width;
7947 width = this.adjustWidth(width); height = this.adjustHeight(height);
7949 this.dom.style.width = this.addUnits(width);
7950 this.dom.style.height = this.addUnits(height);
7952 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7958 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7959 * @param {Number} x X value for new position (coordinates are page-based)
7960 * @param {Number} y Y value for new position (coordinates are page-based)
7961 * @param {Number} width The new width
7962 * @param {Number} height The new height
7963 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7964 * @return {Roo.Element} this
7966 setBounds : function(x, y, width, height, animate){
7968 this.setSize(width, height);
7969 this.setLocation(x, y);
7971 width = this.adjustWidth(width); height = this.adjustHeight(height);
7972 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7973 this.preanim(arguments, 4), 'motion');
7979 * 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.
7980 * @param {Roo.lib.Region} region The region to fill
7981 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7982 * @return {Roo.Element} this
7984 setRegion : function(region, animate){
7985 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7990 * Appends an event handler
7992 * @param {String} eventName The type of event to append
7993 * @param {Function} fn The method the event invokes
7994 * @param {Object} scope (optional) The scope (this object) of the fn
7995 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7997 addListener : function(eventName, fn, scope, options){
7999 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8004 * Removes an event handler from this element
8005 * @param {String} eventName the type of event to remove
8006 * @param {Function} fn the method the event invokes
8007 * @return {Roo.Element} this
8009 removeListener : function(eventName, fn){
8010 Roo.EventManager.removeListener(this.dom, eventName, fn);
8015 * Removes all previous added listeners from this element
8016 * @return {Roo.Element} this
8018 removeAllListeners : function(){
8019 E.purgeElement(this.dom);
8023 relayEvent : function(eventName, observable){
8024 this.on(eventName, function(e){
8025 observable.fireEvent(eventName, e);
8030 * Set the opacity of the element
8031 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8032 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8033 * @return {Roo.Element} this
8035 setOpacity : function(opacity, animate){
8037 var s = this.dom.style;
8040 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8041 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8043 s.opacity = opacity;
8046 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8052 * Gets the left X coordinate
8053 * @param {Boolean} local True to get the local css position instead of page coordinate
8056 getLeft : function(local){
8060 return parseInt(this.getStyle("left"), 10) || 0;
8065 * Gets the right X coordinate of the element (element X position + element width)
8066 * @param {Boolean} local True to get the local css position instead of page coordinate
8069 getRight : function(local){
8071 return this.getX() + this.getWidth();
8073 return (this.getLeft(true) + this.getWidth()) || 0;
8078 * Gets the top Y coordinate
8079 * @param {Boolean} local True to get the local css position instead of page coordinate
8082 getTop : function(local) {
8086 return parseInt(this.getStyle("top"), 10) || 0;
8091 * Gets the bottom Y coordinate of the element (element Y position + element height)
8092 * @param {Boolean} local True to get the local css position instead of page coordinate
8095 getBottom : function(local){
8097 return this.getY() + this.getHeight();
8099 return (this.getTop(true) + this.getHeight()) || 0;
8104 * Initializes positioning on this element. If a desired position is not passed, it will make the
8105 * the element positioned relative IF it is not already positioned.
8106 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8107 * @param {Number} zIndex (optional) The zIndex to apply
8108 * @param {Number} x (optional) Set the page X position
8109 * @param {Number} y (optional) Set the page Y position
8111 position : function(pos, zIndex, x, y){
8113 if(this.getStyle('position') == 'static'){
8114 this.setStyle('position', 'relative');
8117 this.setStyle("position", pos);
8120 this.setStyle("z-index", zIndex);
8122 if(x !== undefined && y !== undefined){
8124 }else if(x !== undefined){
8126 }else if(y !== undefined){
8132 * Clear positioning back to the default when the document was loaded
8133 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8134 * @return {Roo.Element} this
8136 clearPositioning : function(value){
8144 "position" : "static"
8150 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8151 * snapshot before performing an update and then restoring the element.
8154 getPositioning : function(){
8155 var l = this.getStyle("left");
8156 var t = this.getStyle("top");
8158 "position" : this.getStyle("position"),
8160 "right" : l ? "" : this.getStyle("right"),
8162 "bottom" : t ? "" : this.getStyle("bottom"),
8163 "z-index" : this.getStyle("z-index")
8168 * Gets the width of the border(s) for the specified side(s)
8169 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8170 * passing lr would get the border (l)eft width + the border (r)ight width.
8171 * @return {Number} The width of the sides passed added together
8173 getBorderWidth : function(side){
8174 return this.addStyles(side, El.borders);
8178 * Gets the width of the padding(s) for the specified side(s)
8179 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8180 * passing lr would get the padding (l)eft + the padding (r)ight.
8181 * @return {Number} The padding of the sides passed added together
8183 getPadding : function(side){
8184 return this.addStyles(side, El.paddings);
8188 * Set positioning with an object returned by getPositioning().
8189 * @param {Object} posCfg
8190 * @return {Roo.Element} this
8192 setPositioning : function(pc){
8193 this.applyStyles(pc);
8194 if(pc.right == "auto"){
8195 this.dom.style.right = "";
8197 if(pc.bottom == "auto"){
8198 this.dom.style.bottom = "";
8204 fixDisplay : function(){
8205 if(this.getStyle("display") == "none"){
8206 this.setStyle("visibility", "hidden");
8207 this.setStyle("display", this.originalDisplay); // first try reverting to default
8208 if(this.getStyle("display") == "none"){ // if that fails, default to block
8209 this.setStyle("display", "block");
8215 * Quick set left and top adding default units
8216 * @param {String} left The left CSS property value
8217 * @param {String} top The top CSS property value
8218 * @return {Roo.Element} this
8220 setLeftTop : function(left, top){
8221 this.dom.style.left = this.addUnits(left);
8222 this.dom.style.top = this.addUnits(top);
8227 * Move this element relative to its current position.
8228 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8229 * @param {Number} distance How far to move the element in pixels
8230 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8231 * @return {Roo.Element} this
8233 move : function(direction, distance, animate){
8234 var xy = this.getXY();
8235 direction = direction.toLowerCase();
8239 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8243 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8248 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8253 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8260 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8261 * @return {Roo.Element} this
8264 if(!this.isClipped){
8265 this.isClipped = true;
8266 this.originalClip = {
8267 "o": this.getStyle("overflow"),
8268 "x": this.getStyle("overflow-x"),
8269 "y": this.getStyle("overflow-y")
8271 this.setStyle("overflow", "hidden");
8272 this.setStyle("overflow-x", "hidden");
8273 this.setStyle("overflow-y", "hidden");
8279 * Return clipping (overflow) to original clipping before clip() was called
8280 * @return {Roo.Element} this
8282 unclip : function(){
8284 this.isClipped = false;
8285 var o = this.originalClip;
8286 if(o.o){this.setStyle("overflow", o.o);}
8287 if(o.x){this.setStyle("overflow-x", o.x);}
8288 if(o.y){this.setStyle("overflow-y", o.y);}
8295 * Gets the x,y coordinates specified by the anchor position on the element.
8296 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8297 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8298 * {width: (target width), height: (target height)} (defaults to the element's current size)
8299 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8300 * @return {Array} [x, y] An array containing the element's x and y coordinates
8302 getAnchorXY : function(anchor, local, s){
8303 //Passing a different size is useful for pre-calculating anchors,
8304 //especially for anchored animations that change the el size.
8306 var w, h, vp = false;
8309 if(d == document.body || d == document){
8311 w = D.getViewWidth(); h = D.getViewHeight();
8313 w = this.getWidth(); h = this.getHeight();
8316 w = s.width; h = s.height;
8318 var x = 0, y = 0, r = Math.round;
8319 switch((anchor || "tl").toLowerCase()){
8361 var sc = this.getScroll();
8362 return [x + sc.left, y + sc.top];
8364 //Add the element's offset xy
8365 var o = this.getXY();
8366 return [x+o[0], y+o[1]];
8370 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8371 * supported position values.
8372 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8373 * @param {String} position The position to align to.
8374 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8375 * @return {Array} [x, y]
8377 getAlignToXY : function(el, p, o){
8381 throw "Element.alignTo with an element that doesn't exist";
8383 var c = false; //constrain to viewport
8384 var p1 = "", p2 = "";
8391 }else if(p.indexOf("-") == -1){
8394 p = p.toLowerCase();
8395 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8397 throw "Element.alignTo with an invalid alignment " + p;
8399 p1 = m[1]; p2 = m[2]; c = !!m[3];
8401 //Subtract the aligned el's internal xy from the target's offset xy
8402 //plus custom offset to get the aligned el's new offset xy
8403 var a1 = this.getAnchorXY(p1, true);
8404 var a2 = el.getAnchorXY(p2, false);
8405 var x = a2[0] - a1[0] + o[0];
8406 var y = a2[1] - a1[1] + o[1];
8408 //constrain the aligned el to viewport if necessary
8409 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8410 // 5px of margin for ie
8411 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8413 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8414 //perpendicular to the vp border, allow the aligned el to slide on that border,
8415 //otherwise swap the aligned el to the opposite border of the target.
8416 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8417 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8418 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8419 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8422 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8423 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8425 if((x+w) > dw + scrollX){
8426 x = swapX ? r.left-w : dw+scrollX-w;
8429 x = swapX ? r.right : scrollX;
8431 if((y+h) > dh + scrollY){
8432 y = swapY ? r.top-h : dh+scrollY-h;
8435 y = swapY ? r.bottom : scrollY;
8442 getConstrainToXY : function(){
8443 var os = {top:0, left:0, bottom:0, right: 0};
8445 return function(el, local, offsets, proposedXY){
8447 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8449 var vw, vh, vx = 0, vy = 0;
8450 if(el.dom == document.body || el.dom == document){
8451 vw = Roo.lib.Dom.getViewWidth();
8452 vh = Roo.lib.Dom.getViewHeight();
8454 vw = el.dom.clientWidth;
8455 vh = el.dom.clientHeight;
8457 var vxy = el.getXY();
8463 var s = el.getScroll();
8465 vx += offsets.left + s.left;
8466 vy += offsets.top + s.top;
8468 vw -= offsets.right;
8469 vh -= offsets.bottom;
8474 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8475 var x = xy[0], y = xy[1];
8476 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8478 // only move it if it needs it
8481 // first validate right/bottom
8490 // then make sure top/left isn't negative
8499 return moved ? [x, y] : false;
8504 adjustForConstraints : function(xy, parent, offsets){
8505 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8509 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8510 * document it aligns it to the viewport.
8511 * The position parameter is optional, and can be specified in any one of the following formats:
8513 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8514 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8515 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8516 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8517 * <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
8518 * element's anchor point, and the second value is used as the target's anchor point.</li>
8520 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8521 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8522 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8523 * that specified in order to enforce the viewport constraints.
8524 * Following are all of the supported anchor positions:
8527 ----- -----------------------------
8528 tl The top left corner (default)
8529 t The center of the top edge
8530 tr The top right corner
8531 l The center of the left edge
8532 c In the center of the element
8533 r The center of the right edge
8534 bl The bottom left corner
8535 b The center of the bottom edge
8536 br The bottom right corner
8540 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8541 el.alignTo("other-el");
8543 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8544 el.alignTo("other-el", "tr?");
8546 // align the bottom right corner of el with the center left edge of other-el
8547 el.alignTo("other-el", "br-l?");
8549 // align the center of el with the bottom left corner of other-el and
8550 // adjust the x position by -6 pixels (and the y position by 0)
8551 el.alignTo("other-el", "c-bl", [-6, 0]);
8553 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8554 * @param {String} position The position to align to.
8555 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8556 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8557 * @return {Roo.Element} this
8559 alignTo : function(element, position, offsets, animate){
8560 var xy = this.getAlignToXY(element, position, offsets);
8561 this.setXY(xy, this.preanim(arguments, 3));
8566 * Anchors an element to another element and realigns it when the window is resized.
8567 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8568 * @param {String} position The position to align to.
8569 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8570 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8571 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8572 * is a number, it is used as the buffer delay (defaults to 50ms).
8573 * @param {Function} callback The function to call after the animation finishes
8574 * @return {Roo.Element} this
8576 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8577 var action = function(){
8578 this.alignTo(el, alignment, offsets, animate);
8579 Roo.callback(callback, this);
8581 Roo.EventManager.onWindowResize(action, this);
8582 var tm = typeof monitorScroll;
8583 if(tm != 'undefined'){
8584 Roo.EventManager.on(window, 'scroll', action, this,
8585 {buffer: tm == 'number' ? monitorScroll : 50});
8587 action.call(this); // align immediately
8591 * Clears any opacity settings from this element. Required in some cases for IE.
8592 * @return {Roo.Element} this
8594 clearOpacity : function(){
8595 if (window.ActiveXObject) {
8596 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8597 this.dom.style.filter = "";
8600 this.dom.style.opacity = "";
8601 this.dom.style["-moz-opacity"] = "";
8602 this.dom.style["-khtml-opacity"] = "";
8608 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8609 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8610 * @return {Roo.Element} this
8612 hide : function(animate){
8613 this.setVisible(false, this.preanim(arguments, 0));
8618 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8619 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8620 * @return {Roo.Element} this
8622 show : function(animate){
8623 this.setVisible(true, this.preanim(arguments, 0));
8628 * @private Test if size has a unit, otherwise appends the default
8630 addUnits : function(size){
8631 return Roo.Element.addUnits(size, this.defaultUnit);
8635 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8636 * @return {Roo.Element} this
8638 beginMeasure : function(){
8640 if(el.offsetWidth || el.offsetHeight){
8641 return this; // offsets work already
8644 var p = this.dom, b = document.body; // start with this element
8645 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8646 var pe = Roo.get(p);
8647 if(pe.getStyle('display') == 'none'){
8648 changed.push({el: p, visibility: pe.getStyle("visibility")});
8649 p.style.visibility = "hidden";
8650 p.style.display = "block";
8654 this._measureChanged = changed;
8660 * Restores displays to before beginMeasure was called
8661 * @return {Roo.Element} this
8663 endMeasure : function(){
8664 var changed = this._measureChanged;
8666 for(var i = 0, len = changed.length; i < len; i++) {
8668 r.el.style.visibility = r.visibility;
8669 r.el.style.display = "none";
8671 this._measureChanged = null;
8677 * Update the innerHTML of this element, optionally searching for and processing scripts
8678 * @param {String} html The new HTML
8679 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8680 * @param {Function} callback For async script loading you can be noticed when the update completes
8681 * @return {Roo.Element} this
8683 update : function(html, loadScripts, callback){
8684 if(typeof html == "undefined"){
8687 if(loadScripts !== true){
8688 this.dom.innerHTML = html;
8689 if(typeof callback == "function"){
8697 html += '<span id="' + id + '"></span>';
8699 E.onAvailable(id, function(){
8700 var hd = document.getElementsByTagName("head")[0];
8701 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8702 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8703 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8706 while(match = re.exec(html)){
8707 var attrs = match[1];
8708 var srcMatch = attrs ? attrs.match(srcRe) : false;
8709 if(srcMatch && srcMatch[2]){
8710 var s = document.createElement("script");
8711 s.src = srcMatch[2];
8712 var typeMatch = attrs.match(typeRe);
8713 if(typeMatch && typeMatch[2]){
8714 s.type = typeMatch[2];
8717 }else if(match[2] && match[2].length > 0){
8718 if(window.execScript) {
8719 window.execScript(match[2]);
8727 window.eval(match[2]);
8731 var el = document.getElementById(id);
8732 if(el){el.parentNode.removeChild(el);}
8733 if(typeof callback == "function"){
8737 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8742 * Direct access to the UpdateManager update() method (takes the same parameters).
8743 * @param {String/Function} url The url for this request or a function to call to get the url
8744 * @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}
8745 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8746 * @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.
8747 * @return {Roo.Element} this
8750 var um = this.getUpdateManager();
8751 um.update.apply(um, arguments);
8756 * Gets this element's UpdateManager
8757 * @return {Roo.UpdateManager} The UpdateManager
8759 getUpdateManager : function(){
8760 if(!this.updateManager){
8761 this.updateManager = new Roo.UpdateManager(this);
8763 return this.updateManager;
8767 * Disables text selection for this element (normalized across browsers)
8768 * @return {Roo.Element} this
8770 unselectable : function(){
8771 this.dom.unselectable = "on";
8772 this.swallowEvent("selectstart", true);
8773 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8774 this.addClass("x-unselectable");
8779 * Calculates the x, y to center this element on the screen
8780 * @return {Array} The x, y values [x, y]
8782 getCenterXY : function(){
8783 return this.getAlignToXY(document, 'c-c');
8787 * Centers the Element in either the viewport, or another Element.
8788 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8790 center : function(centerIn){
8791 this.alignTo(centerIn || document, 'c-c');
8796 * Tests various css rules/browsers to determine if this element uses a border box
8799 isBorderBox : function(){
8800 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8804 * Return a box {x, y, width, height} that can be used to set another elements
8805 * size/location to match this element.
8806 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8807 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8808 * @return {Object} box An object in the format {x, y, width, height}
8810 getBox : function(contentBox, local){
8815 var left = parseInt(this.getStyle("left"), 10) || 0;
8816 var top = parseInt(this.getStyle("top"), 10) || 0;
8819 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8821 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8823 var l = this.getBorderWidth("l")+this.getPadding("l");
8824 var r = this.getBorderWidth("r")+this.getPadding("r");
8825 var t = this.getBorderWidth("t")+this.getPadding("t");
8826 var b = this.getBorderWidth("b")+this.getPadding("b");
8827 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)};
8829 bx.right = bx.x + bx.width;
8830 bx.bottom = bx.y + bx.height;
8835 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8836 for more information about the sides.
8837 * @param {String} sides
8840 getFrameWidth : function(sides, onlyContentBox){
8841 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8845 * 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.
8846 * @param {Object} box The box to fill {x, y, width, height}
8847 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8848 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8849 * @return {Roo.Element} this
8851 setBox : function(box, adjust, animate){
8852 var w = box.width, h = box.height;
8853 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8854 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8855 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8857 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8862 * Forces the browser to repaint this element
8863 * @return {Roo.Element} this
8865 repaint : function(){
8867 this.addClass("x-repaint");
8868 setTimeout(function(){
8869 Roo.get(dom).removeClass("x-repaint");
8875 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8876 * then it returns the calculated width of the sides (see getPadding)
8877 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8878 * @return {Object/Number}
8880 getMargins : function(side){
8883 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8884 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8885 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8886 right: parseInt(this.getStyle("margin-right"), 10) || 0
8889 return this.addStyles(side, El.margins);
8894 addStyles : function(sides, styles){
8896 for(var i = 0, len = sides.length; i < len; i++){
8897 v = this.getStyle(styles[sides.charAt(i)]);
8899 w = parseInt(v, 10);
8907 * Creates a proxy element of this element
8908 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8909 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8910 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8911 * @return {Roo.Element} The new proxy element
8913 createProxy : function(config, renderTo, matchBox){
8915 renderTo = Roo.getDom(renderTo);
8917 renderTo = document.body;
8919 config = typeof config == "object" ?
8920 config : {tag : "div", cls: config};
8921 var proxy = Roo.DomHelper.append(renderTo, config, true);
8923 proxy.setBox(this.getBox());
8929 * Puts a mask over this element to disable user interaction. Requires core.css.
8930 * This method can only be applied to elements which accept child nodes.
8931 * @param {String} msg (optional) A message to display in the mask
8932 * @param {String} msgCls (optional) A css class to apply to the msg element
8933 * @return {Element} The mask element
8935 mask : function(msg, msgCls)
8937 if(this.getStyle("position") == "static"){
8938 this.setStyle("position", "relative");
8941 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8943 this.addClass("x-masked");
8944 this._mask.setDisplayed(true);
8949 while (dom && dom.style) {
8950 if (!isNaN(parseInt(dom.style.zIndex))) {
8951 z = Math.max(z, parseInt(dom.style.zIndex));
8953 dom = dom.parentNode;
8955 // if we are masking the body - then it hides everything..
8956 if (this.dom == document.body) {
8958 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8959 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8962 if(typeof msg == 'string'){
8964 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8966 var mm = this._maskMsg;
8967 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8968 mm.dom.firstChild.innerHTML = msg;
8969 mm.setDisplayed(true);
8971 mm.setStyle('z-index', z + 102);
8973 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8974 this._mask.setHeight(this.getHeight());
8976 this._mask.setStyle('z-index', z + 100);
8982 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8983 * it is cached for reuse.
8985 unmask : function(removeEl){
8987 if(removeEl === true){
8988 this._mask.remove();
8991 this._maskMsg.remove();
8992 delete this._maskMsg;
8995 this._mask.setDisplayed(false);
8997 this._maskMsg.setDisplayed(false);
9001 this.removeClass("x-masked");
9005 * Returns true if this element is masked
9008 isMasked : function(){
9009 return this._mask && this._mask.isVisible();
9013 * Creates an iframe shim for this element to keep selects and other windowed objects from
9015 * @return {Roo.Element} The new shim element
9017 createShim : function(){
9018 var el = document.createElement('iframe');
9019 el.frameBorder = 'no';
9020 el.className = 'roo-shim';
9021 if(Roo.isIE && Roo.isSecure){
9022 el.src = Roo.SSL_SECURE_URL;
9024 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9025 shim.autoBoxAdjust = false;
9030 * Removes this element from the DOM and deletes it from the cache
9032 remove : function(){
9033 if(this.dom.parentNode){
9034 this.dom.parentNode.removeChild(this.dom);
9036 delete El.cache[this.dom.id];
9040 * Sets up event handlers to add and remove a css class when the mouse is over this element
9041 * @param {String} className
9042 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9043 * mouseout events for children elements
9044 * @return {Roo.Element} this
9046 addClassOnOver : function(className, preventFlicker){
9047 this.on("mouseover", function(){
9048 Roo.fly(this, '_internal').addClass(className);
9050 var removeFn = function(e){
9051 if(preventFlicker !== true || !e.within(this, true)){
9052 Roo.fly(this, '_internal').removeClass(className);
9055 this.on("mouseout", removeFn, this.dom);
9060 * Sets up event handlers to add and remove a css class when this element has the focus
9061 * @param {String} className
9062 * @return {Roo.Element} this
9064 addClassOnFocus : function(className){
9065 this.on("focus", function(){
9066 Roo.fly(this, '_internal').addClass(className);
9068 this.on("blur", function(){
9069 Roo.fly(this, '_internal').removeClass(className);
9074 * 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)
9075 * @param {String} className
9076 * @return {Roo.Element} this
9078 addClassOnClick : function(className){
9080 this.on("mousedown", function(){
9081 Roo.fly(dom, '_internal').addClass(className);
9082 var d = Roo.get(document);
9083 var fn = function(){
9084 Roo.fly(dom, '_internal').removeClass(className);
9085 d.removeListener("mouseup", fn);
9087 d.on("mouseup", fn);
9093 * Stops the specified event from bubbling and optionally prevents the default action
9094 * @param {String} eventName
9095 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9096 * @return {Roo.Element} this
9098 swallowEvent : function(eventName, preventDefault){
9099 var fn = function(e){
9100 e.stopPropagation();
9105 if(eventName instanceof Array){
9106 for(var i = 0, len = eventName.length; i < len; i++){
9107 this.on(eventName[i], fn);
9111 this.on(eventName, fn);
9118 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9121 * Sizes this element to its parent element's dimensions performing
9122 * neccessary box adjustments.
9123 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9124 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9125 * @return {Roo.Element} this
9127 fitToParent : function(monitorResize, targetParent) {
9128 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9129 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9130 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9133 var p = Roo.get(targetParent || this.dom.parentNode);
9134 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9135 if (monitorResize === true) {
9136 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9137 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9143 * Gets the next sibling, skipping text nodes
9144 * @return {HTMLElement} The next sibling or null
9146 getNextSibling : function(){
9147 var n = this.dom.nextSibling;
9148 while(n && n.nodeType != 1){
9155 * Gets the previous sibling, skipping text nodes
9156 * @return {HTMLElement} The previous sibling or null
9158 getPrevSibling : function(){
9159 var n = this.dom.previousSibling;
9160 while(n && n.nodeType != 1){
9161 n = n.previousSibling;
9168 * Appends the passed element(s) to this element
9169 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9170 * @return {Roo.Element} this
9172 appendChild: function(el){
9179 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9180 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9181 * automatically generated with the specified attributes.
9182 * @param {HTMLElement} insertBefore (optional) a child element of this element
9183 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9184 * @return {Roo.Element} The new child element
9186 createChild: function(config, insertBefore, returnDom){
9187 config = config || {tag:'div'};
9189 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9191 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9195 * Appends this element to the passed element
9196 * @param {String/HTMLElement/Element} el The new parent element
9197 * @return {Roo.Element} this
9199 appendTo: function(el){
9200 el = Roo.getDom(el);
9201 el.appendChild(this.dom);
9206 * Inserts this element before the passed element in the DOM
9207 * @param {String/HTMLElement/Element} el The element to insert before
9208 * @return {Roo.Element} this
9210 insertBefore: function(el){
9211 el = Roo.getDom(el);
9212 el.parentNode.insertBefore(this.dom, el);
9217 * Inserts this element after the passed element in the DOM
9218 * @param {String/HTMLElement/Element} el The element to insert after
9219 * @return {Roo.Element} this
9221 insertAfter: function(el){
9222 el = Roo.getDom(el);
9223 el.parentNode.insertBefore(this.dom, el.nextSibling);
9228 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9229 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9230 * @return {Roo.Element} The new child
9232 insertFirst: function(el, returnDom){
9234 if(typeof el == 'object' && !el.nodeType){ // dh config
9235 return this.createChild(el, this.dom.firstChild, returnDom);
9237 el = Roo.getDom(el);
9238 this.dom.insertBefore(el, this.dom.firstChild);
9239 return !returnDom ? Roo.get(el) : el;
9244 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9245 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9246 * @param {String} where (optional) 'before' or 'after' defaults to before
9247 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9248 * @return {Roo.Element} the inserted Element
9250 insertSibling: function(el, where, returnDom){
9251 where = where ? where.toLowerCase() : 'before';
9253 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9255 if(typeof el == 'object' && !el.nodeType){ // dh config
9256 if(where == 'after' && !this.dom.nextSibling){
9257 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9259 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9263 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9264 where == 'before' ? this.dom : this.dom.nextSibling);
9273 * Creates and wraps this element with another element
9274 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9275 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9276 * @return {HTMLElement/Element} The newly created wrapper element
9278 wrap: function(config, returnDom){
9280 config = {tag: "div"};
9282 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9283 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9288 * Replaces the passed element with this element
9289 * @param {String/HTMLElement/Element} el The element to replace
9290 * @return {Roo.Element} this
9292 replace: function(el){
9294 this.insertBefore(el);
9300 * Inserts an html fragment into this element
9301 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9302 * @param {String} html The HTML fragment
9303 * @param {Boolean} returnEl True to return an Roo.Element
9304 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9306 insertHtml : function(where, html, returnEl){
9307 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9308 return returnEl ? Roo.get(el) : el;
9312 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9313 * @param {Object} o The object with the attributes
9314 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9315 * @return {Roo.Element} this
9317 set : function(o, useSet){
9319 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9321 if(attr == "style" || typeof o[attr] == "function") continue;
9323 el.className = o["cls"];
9325 if(useSet) el.setAttribute(attr, o[attr]);
9326 else el[attr] = o[attr];
9330 Roo.DomHelper.applyStyles(el, o.style);
9336 * Convenience method for constructing a KeyMap
9337 * @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:
9338 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9339 * @param {Function} fn The function to call
9340 * @param {Object} scope (optional) The scope of the function
9341 * @return {Roo.KeyMap} The KeyMap created
9343 addKeyListener : function(key, fn, scope){
9345 if(typeof key != "object" || key instanceof Array){
9361 return new Roo.KeyMap(this, config);
9365 * Creates a KeyMap for this element
9366 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9367 * @return {Roo.KeyMap} The KeyMap created
9369 addKeyMap : function(config){
9370 return new Roo.KeyMap(this, config);
9374 * Returns true if this element is scrollable.
9377 isScrollable : function(){
9379 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9383 * 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().
9384 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9385 * @param {Number} value The new scroll value
9386 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9387 * @return {Element} this
9390 scrollTo : function(side, value, animate){
9391 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9393 this.dom[prop] = value;
9395 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9396 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9402 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9403 * within this element's scrollable range.
9404 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9405 * @param {Number} distance How far to scroll the element in pixels
9406 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9407 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9408 * was scrolled as far as it could go.
9410 scroll : function(direction, distance, animate){
9411 if(!this.isScrollable()){
9415 var l = el.scrollLeft, t = el.scrollTop;
9416 var w = el.scrollWidth, h = el.scrollHeight;
9417 var cw = el.clientWidth, ch = el.clientHeight;
9418 direction = direction.toLowerCase();
9419 var scrolled = false;
9420 var a = this.preanim(arguments, 2);
9425 var v = Math.min(l + distance, w-cw);
9426 this.scrollTo("left", v, a);
9433 var v = Math.max(l - distance, 0);
9434 this.scrollTo("left", v, a);
9442 var v = Math.max(t - distance, 0);
9443 this.scrollTo("top", v, a);
9451 var v = Math.min(t + distance, h-ch);
9452 this.scrollTo("top", v, a);
9461 * Translates the passed page coordinates into left/top css values for this element
9462 * @param {Number/Array} x The page x or an array containing [x, y]
9463 * @param {Number} y The page y
9464 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9466 translatePoints : function(x, y){
9467 if(typeof x == 'object' || x instanceof Array){
9470 var p = this.getStyle('position');
9471 var o = this.getXY();
9473 var l = parseInt(this.getStyle('left'), 10);
9474 var t = parseInt(this.getStyle('top'), 10);
9477 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9480 t = (p == "relative") ? 0 : this.dom.offsetTop;
9483 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9487 * Returns the current scroll position of the element.
9488 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9490 getScroll : function(){
9491 var d = this.dom, doc = document;
9492 if(d == doc || d == doc.body){
9493 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9494 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9495 return {left: l, top: t};
9497 return {left: d.scrollLeft, top: d.scrollTop};
9502 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9503 * are convert to standard 6 digit hex color.
9504 * @param {String} attr The css attribute
9505 * @param {String} defaultValue The default value to use when a valid color isn't found
9506 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9509 getColor : function(attr, defaultValue, prefix){
9510 var v = this.getStyle(attr);
9511 if(!v || v == "transparent" || v == "inherit") {
9512 return defaultValue;
9514 var color = typeof prefix == "undefined" ? "#" : prefix;
9515 if(v.substr(0, 4) == "rgb("){
9516 var rvs = v.slice(4, v.length -1).split(",");
9517 for(var i = 0; i < 3; i++){
9518 var h = parseInt(rvs[i]).toString(16);
9525 if(v.substr(0, 1) == "#"){
9527 for(var i = 1; i < 4; i++){
9528 var c = v.charAt(i);
9531 }else if(v.length == 7){
9532 color += v.substr(1);
9536 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9540 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9541 * gradient background, rounded corners and a 4-way shadow.
9542 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9543 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9544 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9545 * @return {Roo.Element} this
9547 boxWrap : function(cls){
9548 cls = cls || 'x-box';
9549 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9550 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9555 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9556 * @param {String} namespace The namespace in which to look for the attribute
9557 * @param {String} name The attribute name
9558 * @return {String} The attribute value
9560 getAttributeNS : Roo.isIE ? function(ns, name){
9562 var type = typeof d[ns+":"+name];
9563 if(type != 'undefined' && type != 'unknown'){
9564 return d[ns+":"+name];
9567 } : function(ns, name){
9569 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9574 * Sets or Returns the value the dom attribute value
9575 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9576 * @param {String} value (optional) The value to set the attribute to
9577 * @return {String} The attribute value
9579 attr : function(name){
9580 if (arguments.length > 1) {
9581 this.dom.setAttribute(name, arguments[1]);
9582 return arguments[1];
9584 if (typeof(name) == 'object') {
9585 for(var i in name) {
9586 this.attr(i, name[i]);
9592 if (!this.dom.hasAttribute(name)) {
9595 return this.dom.getAttribute(name);
9602 var ep = El.prototype;
9605 * Appends an event handler (Shorthand for addListener)
9606 * @param {String} eventName The type of event to append
9607 * @param {Function} fn The method the event invokes
9608 * @param {Object} scope (optional) The scope (this object) of the fn
9609 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9612 ep.on = ep.addListener;
9614 ep.mon = ep.addListener;
9617 * Removes an event handler from this element (shorthand for removeListener)
9618 * @param {String} eventName the type of event to remove
9619 * @param {Function} fn the method the event invokes
9620 * @return {Roo.Element} this
9623 ep.un = ep.removeListener;
9626 * true to automatically adjust width and height settings for box-model issues (default to true)
9628 ep.autoBoxAdjust = true;
9631 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9634 El.addUnits = function(v, defaultUnit){
9635 if(v === "" || v == "auto"){
9638 if(v === undefined){
9641 if(typeof v == "number" || !El.unitPattern.test(v)){
9642 return v + (defaultUnit || 'px');
9647 // special markup used throughout Roo when box wrapping elements
9648 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>';
9650 * Visibility mode constant - Use visibility to hide element
9656 * Visibility mode constant - Use display to hide element
9662 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9663 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9664 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9676 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9677 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9678 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9679 * @return {Element} The Element object
9682 El.get = function(el){
9684 if(!el){ return null; }
9685 if(typeof el == "string"){ // element id
9686 if(!(elm = document.getElementById(el))){
9689 if(ex = El.cache[el]){
9692 ex = El.cache[el] = new El(elm);
9695 }else if(el.tagName){ // dom element
9699 if(ex = El.cache[id]){
9702 ex = El.cache[id] = new El(el);
9705 }else if(el instanceof El){
9707 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9708 // catch case where it hasn't been appended
9709 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9712 }else if(el.isComposite){
9714 }else if(el instanceof Array){
9715 return El.select(el);
9716 }else if(el == document){
9717 // create a bogus element object representing the document object
9719 var f = function(){};
9720 f.prototype = El.prototype;
9722 docEl.dom = document;
9730 El.uncache = function(el){
9731 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9733 delete El.cache[a[i].id || a[i]];
9739 // Garbage collection - uncache elements/purge listeners on orphaned elements
9740 // so we don't hold a reference and cause the browser to retain them
9741 El.garbageCollect = function(){
9742 if(!Roo.enableGarbageCollector){
9743 clearInterval(El.collectorThread);
9746 for(var eid in El.cache){
9747 var el = El.cache[eid], d = el.dom;
9748 // -------------------------------------------------------
9749 // Determining what is garbage:
9750 // -------------------------------------------------------
9752 // dom node is null, definitely garbage
9753 // -------------------------------------------------------
9755 // no parentNode == direct orphan, definitely garbage
9756 // -------------------------------------------------------
9757 // !d.offsetParent && !document.getElementById(eid)
9758 // display none elements have no offsetParent so we will
9759 // also try to look it up by it's id. However, check
9760 // offsetParent first so we don't do unneeded lookups.
9761 // This enables collection of elements that are not orphans
9762 // directly, but somewhere up the line they have an orphan
9764 // -------------------------------------------------------
9765 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9766 delete El.cache[eid];
9767 if(d && Roo.enableListenerCollection){
9773 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9777 El.Flyweight = function(dom){
9780 El.Flyweight.prototype = El.prototype;
9782 El._flyweights = {};
9784 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9785 * the dom node can be overwritten by other code.
9786 * @param {String/HTMLElement} el The dom node or id
9787 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9788 * prevent conflicts (e.g. internally Roo uses "_internal")
9790 * @return {Element} The shared Element object
9792 El.fly = function(el, named){
9793 named = named || '_global';
9794 el = Roo.getDom(el);
9798 if(!El._flyweights[named]){
9799 El._flyweights[named] = new El.Flyweight();
9801 El._flyweights[named].dom = el;
9802 return El._flyweights[named];
9806 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9807 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9808 * Shorthand of {@link Roo.Element#get}
9809 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9810 * @return {Element} The Element object
9816 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9817 * the dom node can be overwritten by other code.
9818 * Shorthand of {@link Roo.Element#fly}
9819 * @param {String/HTMLElement} el The dom node or id
9820 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9821 * prevent conflicts (e.g. internally Roo uses "_internal")
9823 * @return {Element} The shared Element object
9829 // speedy lookup for elements never to box adjust
9830 var noBoxAdjust = Roo.isStrict ? {
9833 input:1, select:1, textarea:1
9835 if(Roo.isIE || Roo.isGecko){
9836 noBoxAdjust['button'] = 1;
9840 Roo.EventManager.on(window, 'unload', function(){
9842 delete El._flyweights;
9850 Roo.Element.selectorFunction = Roo.DomQuery.select;
9853 Roo.Element.select = function(selector, unique, root){
9855 if(typeof selector == "string"){
9856 els = Roo.Element.selectorFunction(selector, root);
9857 }else if(selector.length !== undefined){
9860 throw "Invalid selector";
9862 if(unique === true){
9863 return new Roo.CompositeElement(els);
9865 return new Roo.CompositeElementLite(els);
9869 * Selects elements based on the passed CSS selector to enable working on them as 1.
9870 * @param {String/Array} selector The CSS selector or an array of elements
9871 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9872 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9873 * @return {CompositeElementLite/CompositeElement}
9877 Roo.select = Roo.Element.select;
9894 * Ext JS Library 1.1.1
9895 * Copyright(c) 2006-2007, Ext JS, LLC.
9897 * Originally Released Under LGPL - original licence link has changed is not relivant.
9900 * <script type="text/javascript">
9905 //Notifies Element that fx methods are available
9906 Roo.enableFx = true;
9910 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9911 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9912 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9913 * Element effects to work.</p><br/>
9915 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9916 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9917 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9918 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9919 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9920 * expected results and should be done with care.</p><br/>
9922 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9923 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9926 ----- -----------------------------
9927 tl The top left corner
9928 t The center of the top edge
9929 tr The top right corner
9930 l The center of the left edge
9931 r The center of the right edge
9932 bl The bottom left corner
9933 b The center of the bottom edge
9934 br The bottom right corner
9936 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9937 * below are common options that can be passed to any Fx method.</b>
9938 * @cfg {Function} callback A function called when the effect is finished
9939 * @cfg {Object} scope The scope of the effect function
9940 * @cfg {String} easing A valid Easing value for the effect
9941 * @cfg {String} afterCls A css class to apply after the effect
9942 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9943 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9944 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9945 * effects that end with the element being visually hidden, ignored otherwise)
9946 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9947 * a function which returns such a specification that will be applied to the Element after the effect finishes
9948 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9949 * @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
9950 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9954 * Slides the element into view. An anchor point can be optionally passed to set the point of
9955 * origin for the slide effect. This function automatically handles wrapping the element with
9956 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9959 // default: slide the element in from the top
9962 // custom: slide the element in from the right with a 2-second duration
9963 el.slideIn('r', { duration: 2 });
9965 // common config options shown with default values
9971 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9972 * @param {Object} options (optional) Object literal with any of the Fx config options
9973 * @return {Roo.Element} The Element
9975 slideIn : function(anchor, o){
9976 var el = this.getFxEl();
9979 el.queueFx(o, function(){
9981 anchor = anchor || "t";
9983 // fix display to visibility
9986 // restore values after effect
9987 var r = this.getFxRestore();
9988 var b = this.getBox();
9989 // fixed size for slide
9993 var wrap = this.fxWrap(r.pos, o, "hidden");
9995 var st = this.dom.style;
9996 st.visibility = "visible";
9997 st.position = "absolute";
9999 // clear out temp styles after slide and unwrap
10000 var after = function(){
10001 el.fxUnwrap(wrap, r.pos, o);
10002 st.width = r.width;
10003 st.height = r.height;
10006 // time to calc the positions
10007 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10009 switch(anchor.toLowerCase()){
10011 wrap.setSize(b.width, 0);
10012 st.left = st.bottom = "0";
10016 wrap.setSize(0, b.height);
10017 st.right = st.top = "0";
10021 wrap.setSize(0, b.height);
10022 wrap.setX(b.right);
10023 st.left = st.top = "0";
10024 a = {width: bw, points: pt};
10027 wrap.setSize(b.width, 0);
10028 wrap.setY(b.bottom);
10029 st.left = st.top = "0";
10030 a = {height: bh, points: pt};
10033 wrap.setSize(0, 0);
10034 st.right = st.bottom = "0";
10035 a = {width: bw, height: bh};
10038 wrap.setSize(0, 0);
10039 wrap.setY(b.y+b.height);
10040 st.right = st.top = "0";
10041 a = {width: bw, height: bh, points: pt};
10044 wrap.setSize(0, 0);
10045 wrap.setXY([b.right, b.bottom]);
10046 st.left = st.top = "0";
10047 a = {width: bw, height: bh, points: pt};
10050 wrap.setSize(0, 0);
10051 wrap.setX(b.x+b.width);
10052 st.left = st.bottom = "0";
10053 a = {width: bw, height: bh, points: pt};
10056 this.dom.style.visibility = "visible";
10059 arguments.callee.anim = wrap.fxanim(a,
10069 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10070 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10071 * 'hidden') but block elements will still take up space in the document. The element must be removed
10072 * from the DOM using the 'remove' config option if desired. This function automatically handles
10073 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10076 // default: slide the element out to the top
10079 // custom: slide the element out to the right with a 2-second duration
10080 el.slideOut('r', { duration: 2 });
10082 // common config options shown with default values
10090 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10091 * @param {Object} options (optional) Object literal with any of the Fx config options
10092 * @return {Roo.Element} The Element
10094 slideOut : function(anchor, o){
10095 var el = this.getFxEl();
10098 el.queueFx(o, function(){
10100 anchor = anchor || "t";
10102 // restore values after effect
10103 var r = this.getFxRestore();
10105 var b = this.getBox();
10106 // fixed size for slide
10110 var wrap = this.fxWrap(r.pos, o, "visible");
10112 var st = this.dom.style;
10113 st.visibility = "visible";
10114 st.position = "absolute";
10118 var after = function(){
10120 el.setDisplayed(false);
10125 el.fxUnwrap(wrap, r.pos, o);
10127 st.width = r.width;
10128 st.height = r.height;
10133 var a, zero = {to: 0};
10134 switch(anchor.toLowerCase()){
10136 st.left = st.bottom = "0";
10137 a = {height: zero};
10140 st.right = st.top = "0";
10144 st.left = st.top = "0";
10145 a = {width: zero, points: {to:[b.right, b.y]}};
10148 st.left = st.top = "0";
10149 a = {height: zero, points: {to:[b.x, b.bottom]}};
10152 st.right = st.bottom = "0";
10153 a = {width: zero, height: zero};
10156 st.right = st.top = "0";
10157 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10160 st.left = st.top = "0";
10161 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10164 st.left = st.bottom = "0";
10165 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10169 arguments.callee.anim = wrap.fxanim(a,
10179 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10180 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10181 * The element must be removed from the DOM using the 'remove' config option if desired.
10187 // common config options shown with default values
10195 * @param {Object} options (optional) Object literal with any of the Fx config options
10196 * @return {Roo.Element} The Element
10198 puff : function(o){
10199 var el = this.getFxEl();
10202 el.queueFx(o, function(){
10203 this.clearOpacity();
10206 // restore values after effect
10207 var r = this.getFxRestore();
10208 var st = this.dom.style;
10210 var after = function(){
10212 el.setDisplayed(false);
10219 el.setPositioning(r.pos);
10220 st.width = r.width;
10221 st.height = r.height;
10226 var width = this.getWidth();
10227 var height = this.getHeight();
10229 arguments.callee.anim = this.fxanim({
10230 width : {to: this.adjustWidth(width * 2)},
10231 height : {to: this.adjustHeight(height * 2)},
10232 points : {by: [-(width * .5), -(height * .5)]},
10234 fontSize: {to:200, unit: "%"}
10245 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10246 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10247 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10253 // all config options shown with default values
10261 * @param {Object} options (optional) Object literal with any of the Fx config options
10262 * @return {Roo.Element} The Element
10264 switchOff : function(o){
10265 var el = this.getFxEl();
10268 el.queueFx(o, function(){
10269 this.clearOpacity();
10272 // restore values after effect
10273 var r = this.getFxRestore();
10274 var st = this.dom.style;
10276 var after = function(){
10278 el.setDisplayed(false);
10284 el.setPositioning(r.pos);
10285 st.width = r.width;
10286 st.height = r.height;
10291 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10292 this.clearOpacity();
10296 points:{by:[0, this.getHeight() * .5]}
10297 }, o, 'motion', 0.3, 'easeIn', after);
10298 }).defer(100, this);
10305 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10306 * changed using the "attr" config option) and then fading back to the original color. If no original
10307 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10310 // default: highlight background to yellow
10313 // custom: highlight foreground text to blue for 2 seconds
10314 el.highlight("0000ff", { attr: 'color', duration: 2 });
10316 // common config options shown with default values
10317 el.highlight("ffff9c", {
10318 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10319 endColor: (current color) or "ffffff",
10324 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10325 * @param {Object} options (optional) Object literal with any of the Fx config options
10326 * @return {Roo.Element} The Element
10328 highlight : function(color, o){
10329 var el = this.getFxEl();
10332 el.queueFx(o, function(){
10333 color = color || "ffff9c";
10334 attr = o.attr || "backgroundColor";
10336 this.clearOpacity();
10339 var origColor = this.getColor(attr);
10340 var restoreColor = this.dom.style[attr];
10341 endColor = (o.endColor || origColor) || "ffffff";
10343 var after = function(){
10344 el.dom.style[attr] = restoreColor;
10349 a[attr] = {from: color, to: endColor};
10350 arguments.callee.anim = this.fxanim(a,
10360 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10363 // default: a single light blue ripple
10366 // custom: 3 red ripples lasting 3 seconds total
10367 el.frame("ff0000", 3, { duration: 3 });
10369 // common config options shown with default values
10370 el.frame("C3DAF9", 1, {
10371 duration: 1 //duration of entire animation (not each individual ripple)
10372 // Note: Easing is not configurable and will be ignored if included
10375 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10376 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10377 * @param {Object} options (optional) Object literal with any of the Fx config options
10378 * @return {Roo.Element} The Element
10380 frame : function(color, count, o){
10381 var el = this.getFxEl();
10384 el.queueFx(o, function(){
10385 color = color || "#C3DAF9";
10386 if(color.length == 6){
10387 color = "#" + color;
10389 count = count || 1;
10390 duration = o.duration || 1;
10393 var b = this.getBox();
10394 var animFn = function(){
10395 var proxy = this.createProxy({
10398 visbility:"hidden",
10399 position:"absolute",
10400 "z-index":"35000", // yee haw
10401 border:"0px solid " + color
10404 var scale = Roo.isBorderBox ? 2 : 1;
10406 top:{from:b.y, to:b.y - 20},
10407 left:{from:b.x, to:b.x - 20},
10408 borderWidth:{from:0, to:10},
10409 opacity:{from:1, to:0},
10410 height:{from:b.height, to:(b.height + (20*scale))},
10411 width:{from:b.width, to:(b.width + (20*scale))}
10412 }, duration, function(){
10416 animFn.defer((duration/2)*1000, this);
10427 * Creates a pause before any subsequent queued effects begin. If there are
10428 * no effects queued after the pause it will have no effect.
10433 * @param {Number} seconds The length of time to pause (in seconds)
10434 * @return {Roo.Element} The Element
10436 pause : function(seconds){
10437 var el = this.getFxEl();
10440 el.queueFx(o, function(){
10441 setTimeout(function(){
10443 }, seconds * 1000);
10449 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10450 * using the "endOpacity" config option.
10453 // default: fade in from opacity 0 to 100%
10456 // custom: fade in from opacity 0 to 75% over 2 seconds
10457 el.fadeIn({ endOpacity: .75, duration: 2});
10459 // common config options shown with default values
10461 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10466 * @param {Object} options (optional) Object literal with any of the Fx config options
10467 * @return {Roo.Element} The Element
10469 fadeIn : function(o){
10470 var el = this.getFxEl();
10472 el.queueFx(o, function(){
10473 this.setOpacity(0);
10475 this.dom.style.visibility = 'visible';
10476 var to = o.endOpacity || 1;
10477 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10478 o, null, .5, "easeOut", function(){
10480 this.clearOpacity();
10489 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10490 * using the "endOpacity" config option.
10493 // default: fade out from the element's current opacity to 0
10496 // custom: fade out from the element's current opacity to 25% over 2 seconds
10497 el.fadeOut({ endOpacity: .25, duration: 2});
10499 // common config options shown with default values
10501 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10508 * @param {Object} options (optional) Object literal with any of the Fx config options
10509 * @return {Roo.Element} The Element
10511 fadeOut : function(o){
10512 var el = this.getFxEl();
10514 el.queueFx(o, function(){
10515 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10516 o, null, .5, "easeOut", function(){
10517 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10518 this.dom.style.display = "none";
10520 this.dom.style.visibility = "hidden";
10522 this.clearOpacity();
10530 * Animates the transition of an element's dimensions from a starting height/width
10531 * to an ending height/width.
10534 // change height and width to 100x100 pixels
10535 el.scale(100, 100);
10537 // common config options shown with default values. The height and width will default to
10538 // the element's existing values if passed as null.
10541 [element's height], {
10546 * @param {Number} width The new width (pass undefined to keep the original width)
10547 * @param {Number} height The new height (pass undefined to keep the original height)
10548 * @param {Object} options (optional) Object literal with any of the Fx config options
10549 * @return {Roo.Element} The Element
10551 scale : function(w, h, o){
10552 this.shift(Roo.apply({}, o, {
10560 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10561 * Any of these properties not specified in the config object will not be changed. This effect
10562 * requires that at least one new dimension, position or opacity setting must be passed in on
10563 * the config object in order for the function to have any effect.
10566 // slide the element horizontally to x position 200 while changing the height and opacity
10567 el.shift({ x: 200, height: 50, opacity: .8 });
10569 // common config options shown with default values.
10571 width: [element's width],
10572 height: [element's height],
10573 x: [element's x position],
10574 y: [element's y position],
10575 opacity: [element's opacity],
10580 * @param {Object} options Object literal with any of the Fx config options
10581 * @return {Roo.Element} The Element
10583 shift : function(o){
10584 var el = this.getFxEl();
10586 el.queueFx(o, function(){
10587 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10588 if(w !== undefined){
10589 a.width = {to: this.adjustWidth(w)};
10591 if(h !== undefined){
10592 a.height = {to: this.adjustHeight(h)};
10594 if(x !== undefined || y !== undefined){
10596 x !== undefined ? x : this.getX(),
10597 y !== undefined ? y : this.getY()
10600 if(op !== undefined){
10601 a.opacity = {to: op};
10603 if(o.xy !== undefined){
10604 a.points = {to: o.xy};
10606 arguments.callee.anim = this.fxanim(a,
10607 o, 'motion', .35, "easeOut", function(){
10615 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10616 * ending point of the effect.
10619 // default: slide the element downward while fading out
10622 // custom: slide the element out to the right with a 2-second duration
10623 el.ghost('r', { duration: 2 });
10625 // common config options shown with default values
10633 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10634 * @param {Object} options (optional) Object literal with any of the Fx config options
10635 * @return {Roo.Element} The Element
10637 ghost : function(anchor, o){
10638 var el = this.getFxEl();
10641 el.queueFx(o, function(){
10642 anchor = anchor || "b";
10644 // restore values after effect
10645 var r = this.getFxRestore();
10646 var w = this.getWidth(),
10647 h = this.getHeight();
10649 var st = this.dom.style;
10651 var after = function(){
10653 el.setDisplayed(false);
10659 el.setPositioning(r.pos);
10660 st.width = r.width;
10661 st.height = r.height;
10666 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10667 switch(anchor.toLowerCase()){
10694 arguments.callee.anim = this.fxanim(a,
10704 * Ensures that all effects queued after syncFx is called on the element are
10705 * run concurrently. This is the opposite of {@link #sequenceFx}.
10706 * @return {Roo.Element} The Element
10708 syncFx : function(){
10709 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10718 * Ensures that all effects queued after sequenceFx is called on the element are
10719 * run in sequence. This is the opposite of {@link #syncFx}.
10720 * @return {Roo.Element} The Element
10722 sequenceFx : function(){
10723 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10725 concurrent : false,
10732 nextFx : function(){
10733 var ef = this.fxQueue[0];
10740 * Returns true if the element has any effects actively running or queued, else returns false.
10741 * @return {Boolean} True if element has active effects, else false
10743 hasActiveFx : function(){
10744 return this.fxQueue && this.fxQueue[0];
10748 * Stops any running effects and clears the element's internal effects queue if it contains
10749 * any additional effects that haven't started yet.
10750 * @return {Roo.Element} The Element
10752 stopFx : function(){
10753 if(this.hasActiveFx()){
10754 var cur = this.fxQueue[0];
10755 if(cur && cur.anim && cur.anim.isAnimated()){
10756 this.fxQueue = [cur]; // clear out others
10757 cur.anim.stop(true);
10764 beforeFx : function(o){
10765 if(this.hasActiveFx() && !o.concurrent){
10776 * Returns true if the element is currently blocking so that no other effect can be queued
10777 * until this effect is finished, else returns false if blocking is not set. This is commonly
10778 * used to ensure that an effect initiated by a user action runs to completion prior to the
10779 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10780 * @return {Boolean} True if blocking, else false
10782 hasFxBlock : function(){
10783 var q = this.fxQueue;
10784 return q && q[0] && q[0].block;
10788 queueFx : function(o, fn){
10792 if(!this.hasFxBlock()){
10793 Roo.applyIf(o, this.fxDefaults);
10795 var run = this.beforeFx(o);
10796 fn.block = o.block;
10797 this.fxQueue.push(fn);
10809 fxWrap : function(pos, o, vis){
10811 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10814 wrapXY = this.getXY();
10816 var div = document.createElement("div");
10817 div.style.visibility = vis;
10818 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10819 wrap.setPositioning(pos);
10820 if(wrap.getStyle("position") == "static"){
10821 wrap.position("relative");
10823 this.clearPositioning('auto');
10825 wrap.dom.appendChild(this.dom);
10827 wrap.setXY(wrapXY);
10834 fxUnwrap : function(wrap, pos, o){
10835 this.clearPositioning();
10836 this.setPositioning(pos);
10838 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10844 getFxRestore : function(){
10845 var st = this.dom.style;
10846 return {pos: this.getPositioning(), width: st.width, height : st.height};
10850 afterFx : function(o){
10852 this.applyStyles(o.afterStyle);
10855 this.addClass(o.afterCls);
10857 if(o.remove === true){
10860 Roo.callback(o.callback, o.scope, [this]);
10862 this.fxQueue.shift();
10868 getFxEl : function(){ // support for composite element fx
10869 return Roo.get(this.dom);
10873 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10874 animType = animType || 'run';
10876 var anim = Roo.lib.Anim[animType](
10878 (opt.duration || defaultDur) || .35,
10879 (opt.easing || defaultEase) || 'easeOut',
10881 Roo.callback(cb, this);
10890 // backwords compat
10891 Roo.Fx.resize = Roo.Fx.scale;
10893 //When included, Roo.Fx is automatically applied to Element so that all basic
10894 //effects are available directly via the Element API
10895 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10897 * Ext JS Library 1.1.1
10898 * Copyright(c) 2006-2007, Ext JS, LLC.
10900 * Originally Released Under LGPL - original licence link has changed is not relivant.
10903 * <script type="text/javascript">
10908 * @class Roo.CompositeElement
10909 * Standard composite class. Creates a Roo.Element for every element in the collection.
10911 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10912 * actions will be performed on all the elements in this collection.</b>
10914 * All methods return <i>this</i> and can be chained.
10916 var els = Roo.select("#some-el div.some-class", true);
10917 // or select directly from an existing element
10918 var el = Roo.get('some-el');
10919 el.select('div.some-class', true);
10921 els.setWidth(100); // all elements become 100 width
10922 els.hide(true); // all elements fade out and hide
10924 els.setWidth(100).hide(true);
10927 Roo.CompositeElement = function(els){
10928 this.elements = [];
10929 this.addElements(els);
10931 Roo.CompositeElement.prototype = {
10933 addElements : function(els){
10934 if(!els) return this;
10935 if(typeof els == "string"){
10936 els = Roo.Element.selectorFunction(els);
10938 var yels = this.elements;
10939 var index = yels.length-1;
10940 for(var i = 0, len = els.length; i < len; i++) {
10941 yels[++index] = Roo.get(els[i]);
10947 * Clears this composite and adds the elements returned by the passed selector.
10948 * @param {String/Array} els A string CSS selector, an array of elements or an element
10949 * @return {CompositeElement} this
10951 fill : function(els){
10952 this.elements = [];
10958 * Filters this composite to only elements that match the passed selector.
10959 * @param {String} selector A string CSS selector
10960 * @param {Boolean} inverse return inverse filter (not matches)
10961 * @return {CompositeElement} this
10963 filter : function(selector, inverse){
10965 inverse = inverse || false;
10966 this.each(function(el){
10967 var match = inverse ? !el.is(selector) : el.is(selector);
10969 els[els.length] = el.dom;
10976 invoke : function(fn, args){
10977 var els = this.elements;
10978 for(var i = 0, len = els.length; i < len; i++) {
10979 Roo.Element.prototype[fn].apply(els[i], args);
10984 * Adds elements to this composite.
10985 * @param {String/Array} els A string CSS selector, an array of elements or an element
10986 * @return {CompositeElement} this
10988 add : function(els){
10989 if(typeof els == "string"){
10990 this.addElements(Roo.Element.selectorFunction(els));
10991 }else if(els.length !== undefined){
10992 this.addElements(els);
10994 this.addElements([els]);
10999 * Calls the passed function passing (el, this, index) for each element in this composite.
11000 * @param {Function} fn The function to call
11001 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11002 * @return {CompositeElement} this
11004 each : function(fn, scope){
11005 var els = this.elements;
11006 for(var i = 0, len = els.length; i < len; i++){
11007 if(fn.call(scope || els[i], els[i], this, i) === false) {
11015 * Returns the Element object at the specified index
11016 * @param {Number} index
11017 * @return {Roo.Element}
11019 item : function(index){
11020 return this.elements[index] || null;
11024 * Returns the first Element
11025 * @return {Roo.Element}
11027 first : function(){
11028 return this.item(0);
11032 * Returns the last Element
11033 * @return {Roo.Element}
11036 return this.item(this.elements.length-1);
11040 * Returns the number of elements in this composite
11043 getCount : function(){
11044 return this.elements.length;
11048 * Returns true if this composite contains the passed element
11051 contains : function(el){
11052 return this.indexOf(el) !== -1;
11056 * Returns true if this composite contains the passed element
11059 indexOf : function(el){
11060 return this.elements.indexOf(Roo.get(el));
11065 * Removes the specified element(s).
11066 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11067 * or an array of any of those.
11068 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11069 * @return {CompositeElement} this
11071 removeElement : function(el, removeDom){
11072 if(el instanceof Array){
11073 for(var i = 0, len = el.length; i < len; i++){
11074 this.removeElement(el[i]);
11078 var index = typeof el == 'number' ? el : this.indexOf(el);
11081 var d = this.elements[index];
11085 d.parentNode.removeChild(d);
11088 this.elements.splice(index, 1);
11094 * Replaces the specified element with the passed element.
11095 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11097 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11098 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11099 * @return {CompositeElement} this
11101 replaceElement : function(el, replacement, domReplace){
11102 var index = typeof el == 'number' ? el : this.indexOf(el);
11105 this.elements[index].replaceWith(replacement);
11107 this.elements.splice(index, 1, Roo.get(replacement))
11114 * Removes all elements.
11116 clear : function(){
11117 this.elements = [];
11121 Roo.CompositeElement.createCall = function(proto, fnName){
11122 if(!proto[fnName]){
11123 proto[fnName] = function(){
11124 return this.invoke(fnName, arguments);
11128 for(var fnName in Roo.Element.prototype){
11129 if(typeof Roo.Element.prototype[fnName] == "function"){
11130 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11136 * Ext JS Library 1.1.1
11137 * Copyright(c) 2006-2007, Ext JS, LLC.
11139 * Originally Released Under LGPL - original licence link has changed is not relivant.
11142 * <script type="text/javascript">
11146 * @class Roo.CompositeElementLite
11147 * @extends Roo.CompositeElement
11148 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11150 var els = Roo.select("#some-el div.some-class");
11151 // or select directly from an existing element
11152 var el = Roo.get('some-el');
11153 el.select('div.some-class');
11155 els.setWidth(100); // all elements become 100 width
11156 els.hide(true); // all elements fade out and hide
11158 els.setWidth(100).hide(true);
11159 </code></pre><br><br>
11160 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11161 * actions will be performed on all the elements in this collection.</b>
11163 Roo.CompositeElementLite = function(els){
11164 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11165 this.el = new Roo.Element.Flyweight();
11167 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11168 addElements : function(els){
11170 if(els instanceof Array){
11171 this.elements = this.elements.concat(els);
11173 var yels = this.elements;
11174 var index = yels.length-1;
11175 for(var i = 0, len = els.length; i < len; i++) {
11176 yels[++index] = els[i];
11182 invoke : function(fn, args){
11183 var els = this.elements;
11185 for(var i = 0, len = els.length; i < len; i++) {
11187 Roo.Element.prototype[fn].apply(el, args);
11192 * Returns a flyweight Element of the dom element object at the specified index
11193 * @param {Number} index
11194 * @return {Roo.Element}
11196 item : function(index){
11197 if(!this.elements[index]){
11200 this.el.dom = this.elements[index];
11204 // fixes scope with flyweight
11205 addListener : function(eventName, handler, scope, opt){
11206 var els = this.elements;
11207 for(var i = 0, len = els.length; i < len; i++) {
11208 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11214 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11215 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11216 * a reference to the dom node, use el.dom.</b>
11217 * @param {Function} fn The function to call
11218 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11219 * @return {CompositeElement} this
11221 each : function(fn, scope){
11222 var els = this.elements;
11224 for(var i = 0, len = els.length; i < len; i++){
11226 if(fn.call(scope || el, el, this, i) === false){
11233 indexOf : function(el){
11234 return this.elements.indexOf(Roo.getDom(el));
11237 replaceElement : function(el, replacement, domReplace){
11238 var index = typeof el == 'number' ? el : this.indexOf(el);
11240 replacement = Roo.getDom(replacement);
11242 var d = this.elements[index];
11243 d.parentNode.insertBefore(replacement, d);
11244 d.parentNode.removeChild(d);
11246 this.elements.splice(index, 1, replacement);
11251 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11255 * Ext JS Library 1.1.1
11256 * Copyright(c) 2006-2007, Ext JS, LLC.
11258 * Originally Released Under LGPL - original licence link has changed is not relivant.
11261 * <script type="text/javascript">
11267 * @class Roo.data.Connection
11268 * @extends Roo.util.Observable
11269 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11270 * either to a configured URL, or to a URL specified at request time.<br><br>
11272 * Requests made by this class are asynchronous, and will return immediately. No data from
11273 * the server will be available to the statement immediately following the {@link #request} call.
11274 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11276 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11277 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11278 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11279 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11280 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11281 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11282 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11283 * standard DOM methods.
11285 * @param {Object} config a configuration object.
11287 Roo.data.Connection = function(config){
11288 Roo.apply(this, config);
11291 * @event beforerequest
11292 * Fires before a network request is made to retrieve a data object.
11293 * @param {Connection} conn This Connection object.
11294 * @param {Object} options The options config object passed to the {@link #request} method.
11296 "beforerequest" : true,
11298 * @event requestcomplete
11299 * Fires if the request was successfully completed.
11300 * @param {Connection} conn This Connection object.
11301 * @param {Object} response The XHR object containing the response data.
11302 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11303 * @param {Object} options The options config object passed to the {@link #request} method.
11305 "requestcomplete" : true,
11307 * @event requestexception
11308 * Fires if an error HTTP status was returned from the server.
11309 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11310 * @param {Connection} conn This Connection object.
11311 * @param {Object} response The XHR object containing the response data.
11312 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11313 * @param {Object} options The options config object passed to the {@link #request} method.
11315 "requestexception" : true
11317 Roo.data.Connection.superclass.constructor.call(this);
11320 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11322 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11325 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11326 * extra parameters to each request made by this object. (defaults to undefined)
11329 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11330 * to each request made by this object. (defaults to undefined)
11333 * @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)
11336 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11340 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11346 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11349 disableCaching: true,
11352 * Sends an HTTP request to a remote server.
11353 * @param {Object} options An object which may contain the following properties:<ul>
11354 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11355 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11356 * request, a url encoded string or a function to call to get either.</li>
11357 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11358 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11359 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11360 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11361 * <li>options {Object} The parameter to the request call.</li>
11362 * <li>success {Boolean} True if the request succeeded.</li>
11363 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11365 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11366 * The callback is passed the following parameters:<ul>
11367 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11368 * <li>options {Object} The parameter to the request call.</li>
11370 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11371 * The callback is passed the following parameters:<ul>
11372 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11373 * <li>options {Object} The parameter to the request call.</li>
11375 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11376 * for the callback function. Defaults to the browser window.</li>
11377 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11378 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11379 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11380 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11381 * params for the post data. Any params will be appended to the URL.</li>
11382 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11384 * @return {Number} transactionId
11386 request : function(o){
11387 if(this.fireEvent("beforerequest", this, o) !== false){
11390 if(typeof p == "function"){
11391 p = p.call(o.scope||window, o);
11393 if(typeof p == "object"){
11394 p = Roo.urlEncode(o.params);
11396 if(this.extraParams){
11397 var extras = Roo.urlEncode(this.extraParams);
11398 p = p ? (p + '&' + extras) : extras;
11401 var url = o.url || this.url;
11402 if(typeof url == 'function'){
11403 url = url.call(o.scope||window, o);
11407 var form = Roo.getDom(o.form);
11408 url = url || form.action;
11410 var enctype = form.getAttribute("enctype");
11411 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11412 return this.doFormUpload(o, p, url);
11414 var f = Roo.lib.Ajax.serializeForm(form);
11415 p = p ? (p + '&' + f) : f;
11418 var hs = o.headers;
11419 if(this.defaultHeaders){
11420 hs = Roo.apply(hs || {}, this.defaultHeaders);
11427 success: this.handleResponse,
11428 failure: this.handleFailure,
11430 argument: {options: o},
11431 timeout : o.timeout || this.timeout
11434 var method = o.method||this.method||(p ? "POST" : "GET");
11436 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11437 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11440 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11444 }else if(this.autoAbort !== false){
11448 if((method == 'GET' && p) || o.xmlData){
11449 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11452 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11453 return this.transId;
11455 Roo.callback(o.callback, o.scope, [o, null, null]);
11461 * Determine whether this object has a request outstanding.
11462 * @param {Number} transactionId (Optional) defaults to the last transaction
11463 * @return {Boolean} True if there is an outstanding request.
11465 isLoading : function(transId){
11467 return Roo.lib.Ajax.isCallInProgress(transId);
11469 return this.transId ? true : false;
11474 * Aborts any outstanding request.
11475 * @param {Number} transactionId (Optional) defaults to the last transaction
11477 abort : function(transId){
11478 if(transId || this.isLoading()){
11479 Roo.lib.Ajax.abort(transId || this.transId);
11484 handleResponse : function(response){
11485 this.transId = false;
11486 var options = response.argument.options;
11487 response.argument = options ? options.argument : null;
11488 this.fireEvent("requestcomplete", this, response, options);
11489 Roo.callback(options.success, options.scope, [response, options]);
11490 Roo.callback(options.callback, options.scope, [options, true, response]);
11494 handleFailure : function(response, e){
11495 this.transId = false;
11496 var options = response.argument.options;
11497 response.argument = options ? options.argument : null;
11498 this.fireEvent("requestexception", this, response, options, e);
11499 Roo.callback(options.failure, options.scope, [response, options]);
11500 Roo.callback(options.callback, options.scope, [options, false, response]);
11504 doFormUpload : function(o, ps, url){
11506 var frame = document.createElement('iframe');
11509 frame.className = 'x-hidden';
11511 frame.src = Roo.SSL_SECURE_URL;
11513 document.body.appendChild(frame);
11516 document.frames[id].name = id;
11519 var form = Roo.getDom(o.form);
11521 form.method = 'POST';
11522 form.enctype = form.encoding = 'multipart/form-data';
11528 if(ps){ // add dynamic params
11530 ps = Roo.urlDecode(ps, false);
11532 if(ps.hasOwnProperty(k)){
11533 hd = document.createElement('input');
11534 hd.type = 'hidden';
11537 form.appendChild(hd);
11544 var r = { // bogus response object
11549 r.argument = o ? o.argument : null;
11554 doc = frame.contentWindow.document;
11556 doc = (frame.contentDocument || window.frames[id].document);
11558 if(doc && doc.body){
11559 r.responseText = doc.body.innerHTML;
11561 if(doc && doc.XMLDocument){
11562 r.responseXML = doc.XMLDocument;
11564 r.responseXML = doc;
11571 Roo.EventManager.removeListener(frame, 'load', cb, this);
11573 this.fireEvent("requestcomplete", this, r, o);
11574 Roo.callback(o.success, o.scope, [r, o]);
11575 Roo.callback(o.callback, o.scope, [o, true, r]);
11577 setTimeout(function(){document.body.removeChild(frame);}, 100);
11580 Roo.EventManager.on(frame, 'load', cb, this);
11583 if(hiddens){ // remove dynamic params
11584 for(var i = 0, len = hiddens.length; i < len; i++){
11585 form.removeChild(hiddens[i]);
11592 * Ext JS Library 1.1.1
11593 * Copyright(c) 2006-2007, Ext JS, LLC.
11595 * Originally Released Under LGPL - original licence link has changed is not relivant.
11598 * <script type="text/javascript">
11602 * Global Ajax request class.
11605 * @extends Roo.data.Connection
11608 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11609 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11610 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11611 * @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)
11612 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11613 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11614 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11616 Roo.Ajax = new Roo.data.Connection({
11625 * Serialize the passed form into a url encoded string
11627 * @param {String/HTMLElement} form
11630 serializeForm : function(form){
11631 return Roo.lib.Ajax.serializeForm(form);
11635 * Ext JS Library 1.1.1
11636 * Copyright(c) 2006-2007, Ext JS, LLC.
11638 * Originally Released Under LGPL - original licence link has changed is not relivant.
11641 * <script type="text/javascript">
11646 * @class Roo.UpdateManager
11647 * @extends Roo.util.Observable
11648 * Provides AJAX-style update for Element object.<br><br>
11651 * // Get it from a Roo.Element object
11652 * var el = Roo.get("foo");
11653 * var mgr = el.getUpdateManager();
11654 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11656 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11658 * // or directly (returns the same UpdateManager instance)
11659 * var mgr = new Roo.UpdateManager("myElementId");
11660 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11661 * mgr.on("update", myFcnNeedsToKnow);
11663 // short handed call directly from the element object
11664 Roo.get("foo").load({
11668 text: "Loading Foo..."
11672 * Create new UpdateManager directly.
11673 * @param {String/HTMLElement/Roo.Element} el The element to update
11674 * @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).
11676 Roo.UpdateManager = function(el, forceNew){
11678 if(!forceNew && el.updateManager){
11679 return el.updateManager;
11682 * The Element object
11683 * @type Roo.Element
11687 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11690 this.defaultUrl = null;
11694 * @event beforeupdate
11695 * Fired before an update is made, return false from your handler and the update is cancelled.
11696 * @param {Roo.Element} el
11697 * @param {String/Object/Function} url
11698 * @param {String/Object} params
11700 "beforeupdate": true,
11703 * Fired after successful update is made.
11704 * @param {Roo.Element} el
11705 * @param {Object} oResponseObject The response Object
11710 * Fired on update failure.
11711 * @param {Roo.Element} el
11712 * @param {Object} oResponseObject The response Object
11716 var d = Roo.UpdateManager.defaults;
11718 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11721 this.sslBlankUrl = d.sslBlankUrl;
11723 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11726 this.disableCaching = d.disableCaching;
11728 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11731 this.indicatorText = d.indicatorText;
11733 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11736 this.showLoadIndicator = d.showLoadIndicator;
11738 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11741 this.timeout = d.timeout;
11744 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11747 this.loadScripts = d.loadScripts;
11750 * Transaction object of current executing transaction
11752 this.transaction = null;
11757 this.autoRefreshProcId = null;
11759 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11762 this.refreshDelegate = this.refresh.createDelegate(this);
11764 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11767 this.updateDelegate = this.update.createDelegate(this);
11769 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11772 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11776 this.successDelegate = this.processSuccess.createDelegate(this);
11780 this.failureDelegate = this.processFailure.createDelegate(this);
11782 if(!this.renderer){
11784 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11786 this.renderer = new Roo.UpdateManager.BasicRenderer();
11789 Roo.UpdateManager.superclass.constructor.call(this);
11792 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11794 * Get the Element this UpdateManager is bound to
11795 * @return {Roo.Element} The element
11797 getEl : function(){
11801 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11802 * @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:
11805 url: "your-url.php",<br/>
11806 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11807 callback: yourFunction,<br/>
11808 scope: yourObject, //(optional scope) <br/>
11809 discardUrl: false, <br/>
11810 nocache: false,<br/>
11811 text: "Loading...",<br/>
11813 scripts: false<br/>
11816 * The only required property is url. The optional properties nocache, text and scripts
11817 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11818 * @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}
11819 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11820 * @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.
11822 update : function(url, params, callback, discardUrl){
11823 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11824 var method = this.method,
11826 if(typeof url == "object"){ // must be config object
11829 params = params || cfg.params;
11830 callback = callback || cfg.callback;
11831 discardUrl = discardUrl || cfg.discardUrl;
11832 if(callback && cfg.scope){
11833 callback = callback.createDelegate(cfg.scope);
11835 if(typeof cfg.method != "undefined"){method = cfg.method;};
11836 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11837 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11838 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11839 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11841 this.showLoading();
11843 this.defaultUrl = url;
11845 if(typeof url == "function"){
11846 url = url.call(this);
11849 method = method || (params ? "POST" : "GET");
11850 if(method == "GET"){
11851 url = this.prepareUrl(url);
11854 var o = Roo.apply(cfg ||{}, {
11857 success: this.successDelegate,
11858 failure: this.failureDelegate,
11859 callback: undefined,
11860 timeout: (this.timeout*1000),
11861 argument: {"url": url, "form": null, "callback": callback, "params": params}
11863 Roo.log("updated manager called with timeout of " + o.timeout);
11864 this.transaction = Roo.Ajax.request(o);
11869 * 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.
11870 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11871 * @param {String/HTMLElement} form The form Id or form element
11872 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11873 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11874 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11876 formUpdate : function(form, url, reset, callback){
11877 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11878 if(typeof url == "function"){
11879 url = url.call(this);
11881 form = Roo.getDom(form);
11882 this.transaction = Roo.Ajax.request({
11885 success: this.successDelegate,
11886 failure: this.failureDelegate,
11887 timeout: (this.timeout*1000),
11888 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11890 this.showLoading.defer(1, this);
11895 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11896 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11898 refresh : function(callback){
11899 if(this.defaultUrl == null){
11902 this.update(this.defaultUrl, null, callback, true);
11906 * Set this element to auto refresh.
11907 * @param {Number} interval How often to update (in seconds).
11908 * @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)
11909 * @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}
11910 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11911 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11913 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11915 this.update(url || this.defaultUrl, params, callback, true);
11917 if(this.autoRefreshProcId){
11918 clearInterval(this.autoRefreshProcId);
11920 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11924 * Stop auto refresh on this element.
11926 stopAutoRefresh : function(){
11927 if(this.autoRefreshProcId){
11928 clearInterval(this.autoRefreshProcId);
11929 delete this.autoRefreshProcId;
11933 isAutoRefreshing : function(){
11934 return this.autoRefreshProcId ? true : false;
11937 * Called to update the element to "Loading" state. Override to perform custom action.
11939 showLoading : function(){
11940 if(this.showLoadIndicator){
11941 this.el.update(this.indicatorText);
11946 * Adds unique parameter to query string if disableCaching = true
11949 prepareUrl : function(url){
11950 if(this.disableCaching){
11951 var append = "_dc=" + (new Date().getTime());
11952 if(url.indexOf("?") !== -1){
11953 url += "&" + append;
11955 url += "?" + append;
11964 processSuccess : function(response){
11965 this.transaction = null;
11966 if(response.argument.form && response.argument.reset){
11967 try{ // put in try/catch since some older FF releases had problems with this
11968 response.argument.form.reset();
11971 if(this.loadScripts){
11972 this.renderer.render(this.el, response, this,
11973 this.updateComplete.createDelegate(this, [response]));
11975 this.renderer.render(this.el, response, this);
11976 this.updateComplete(response);
11980 updateComplete : function(response){
11981 this.fireEvent("update", this.el, response);
11982 if(typeof response.argument.callback == "function"){
11983 response.argument.callback(this.el, true, response);
11990 processFailure : function(response){
11991 this.transaction = null;
11992 this.fireEvent("failure", this.el, response);
11993 if(typeof response.argument.callback == "function"){
11994 response.argument.callback(this.el, false, response);
11999 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12000 * @param {Object} renderer The object implementing the render() method
12002 setRenderer : function(renderer){
12003 this.renderer = renderer;
12006 getRenderer : function(){
12007 return this.renderer;
12011 * Set the defaultUrl used for updates
12012 * @param {String/Function} defaultUrl The url or a function to call to get the url
12014 setDefaultUrl : function(defaultUrl){
12015 this.defaultUrl = defaultUrl;
12019 * Aborts the executing transaction
12021 abort : function(){
12022 if(this.transaction){
12023 Roo.Ajax.abort(this.transaction);
12028 * Returns true if an update is in progress
12029 * @return {Boolean}
12031 isUpdating : function(){
12032 if(this.transaction){
12033 return Roo.Ajax.isLoading(this.transaction);
12040 * @class Roo.UpdateManager.defaults
12041 * @static (not really - but it helps the doc tool)
12042 * The defaults collection enables customizing the default properties of UpdateManager
12044 Roo.UpdateManager.defaults = {
12046 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12052 * True to process scripts by default (Defaults to false).
12055 loadScripts : false,
12058 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12061 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12063 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12066 disableCaching : false,
12068 * Whether to show indicatorText when loading (Defaults to true).
12071 showLoadIndicator : true,
12073 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12076 indicatorText : '<div class="loading-indicator">Loading...</div>'
12080 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12082 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12083 * @param {String/HTMLElement/Roo.Element} el The element to update
12084 * @param {String} url The url
12085 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12086 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12089 * @member Roo.UpdateManager
12091 Roo.UpdateManager.updateElement = function(el, url, params, options){
12092 var um = Roo.get(el, true).getUpdateManager();
12093 Roo.apply(um, options);
12094 um.update(url, params, options ? options.callback : null);
12096 // alias for backwards compat
12097 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12099 * @class Roo.UpdateManager.BasicRenderer
12100 * Default Content renderer. Updates the elements innerHTML with the responseText.
12102 Roo.UpdateManager.BasicRenderer = function(){};
12104 Roo.UpdateManager.BasicRenderer.prototype = {
12106 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12107 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12108 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12109 * @param {Roo.Element} el The element being rendered
12110 * @param {Object} response The YUI Connect response object
12111 * @param {UpdateManager} updateManager The calling update manager
12112 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12114 render : function(el, response, updateManager, callback){
12115 el.update(response.responseText, updateManager.loadScripts, callback);
12121 * (c)) Alan Knowles
12127 * @class Roo.DomTemplate
12128 * @extends Roo.Template
12129 * An effort at a dom based template engine..
12131 * Similar to XTemplate, except it uses dom parsing to create the template..
12133 * Supported features:
12138 {a_variable} - output encoded.
12139 {a_variable.format:("Y-m-d")} - call a method on the variable
12140 {a_variable:raw} - unencoded output
12141 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12142 {a_variable:this.method_on_template(...)} - call a method on the template object.
12147 <div roo-for="a_variable or condition.."></div>
12148 <div roo-if="a_variable or condition"></div>
12149 <div roo-exec="some javascript"></div>
12150 <div roo-name="named_template"></div>
12155 Roo.DomTemplate = function()
12157 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12164 Roo.extend(Roo.DomTemplate, Roo.Template, {
12166 * id counter for sub templates.
12170 * flag to indicate if dom parser is inside a pre,
12171 * it will strip whitespace if not.
12176 * The various sub templates
12184 * basic tag replacing syntax
12187 * // you can fake an object call by doing this
12191 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12192 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12194 iterChild : function (node, method) {
12196 var oldPre = this.inPre;
12197 if (node.tagName == 'PRE') {
12200 for( var i = 0; i < node.childNodes.length; i++) {
12201 method.call(this, node.childNodes[i]);
12203 this.inPre = oldPre;
12209 * compile the template
12211 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12214 compile: function()
12218 // covert the html into DOM...
12222 doc = document.implementation.createHTMLDocument("");
12223 doc.documentElement.innerHTML = this.html ;
12224 div = doc.documentElement;
12226 // old IE... - nasty -- it causes all sorts of issues.. with
12227 // images getting pulled from server..
12228 div = document.createElement('div');
12229 div.innerHTML = this.html;
12231 //doc.documentElement.innerHTML = htmlBody
12237 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12239 var tpls = this.tpls;
12241 // create a top level template from the snippet..
12243 //Roo.log(div.innerHTML);
12250 body : div.innerHTML,
12263 Roo.each(tpls, function(tp){
12264 this.compileTpl(tp);
12265 this.tpls[tp.id] = tp;
12268 this.master = tpls[0];
12274 compileNode : function(node, istop) {
12279 // skip anything not a tag..
12280 if (node.nodeType != 1) {
12281 if (node.nodeType == 3 && !this.inPre) {
12282 // reduce white space..
12283 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12306 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12307 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12308 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12309 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12315 // just itterate children..
12316 this.iterChild(node,this.compileNode);
12319 tpl.uid = this.id++;
12320 tpl.value = node.getAttribute('roo-' + tpl.attr);
12321 node.removeAttribute('roo-'+ tpl.attr);
12322 if (tpl.attr != 'name') {
12323 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12324 node.parentNode.replaceChild(placeholder, node);
12327 var placeholder = document.createElement('span');
12328 placeholder.className = 'roo-tpl-' + tpl.value;
12329 node.parentNode.replaceChild(placeholder, node);
12332 // parent now sees '{domtplXXXX}
12333 this.iterChild(node,this.compileNode);
12335 // we should now have node body...
12336 var div = document.createElement('div');
12337 div.appendChild(node);
12339 // this has the unfortunate side effect of converting tagged attributes
12340 // eg. href="{...}" into %7C...%7D
12341 // this has been fixed by searching for those combo's although it's a bit hacky..
12344 tpl.body = div.innerHTML;
12351 switch (tpl.value) {
12352 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12353 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12354 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12359 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12363 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12367 tpl.id = tpl.value; // replace non characters???
12373 this.tpls.push(tpl);
12383 * Compile a segment of the template into a 'sub-template'
12389 compileTpl : function(tpl)
12391 var fm = Roo.util.Format;
12392 var useF = this.disableFormats !== true;
12394 var sep = Roo.isGecko ? "+\n" : ",\n";
12396 var undef = function(str) {
12397 Roo.debug && Roo.log("Property not found :" + str);
12401 //Roo.log(tpl.body);
12405 var fn = function(m, lbrace, name, format, args)
12408 //Roo.log(arguments);
12409 args = args ? args.replace(/\\'/g,"'") : args;
12410 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12411 if (typeof(format) == 'undefined') {
12412 format = 'htmlEncode';
12414 if (format == 'raw' ) {
12418 if(name.substr(0, 6) == 'domtpl'){
12419 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12422 // build an array of options to determine if value is undefined..
12424 // basically get 'xxxx.yyyy' then do
12425 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12426 // (function () { Roo.log("Property not found"); return ''; })() :
12431 Roo.each(name.split('.'), function(st) {
12432 lookfor += (lookfor.length ? '.': '') + st;
12433 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12436 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12439 if(format && useF){
12441 args = args ? ',' + args : "";
12443 if(format.substr(0, 5) != "this."){
12444 format = "fm." + format + '(';
12446 format = 'this.call("'+ format.substr(5) + '", ';
12450 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12453 if (args && args.length) {
12454 // called with xxyx.yuu:(test,test)
12456 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12458 // raw.. - :raw modifier..
12459 return "'"+ sep + udef_st + name + ")"+sep+"'";
12463 // branched to use + in gecko and [].join() in others
12465 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12466 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12469 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12470 body.push(tpl.body.replace(/(\r\n|\n)/g,
12471 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12472 body.push("'].join('');};};");
12473 body = body.join('');
12476 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12478 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12485 * same as applyTemplate, except it's done to one of the subTemplates
12486 * when using named templates, you can do:
12488 * var str = pl.applySubTemplate('your-name', values);
12491 * @param {Number} id of the template
12492 * @param {Object} values to apply to template
12493 * @param {Object} parent (normaly the instance of this object)
12495 applySubTemplate : function(id, values, parent)
12499 var t = this.tpls[id];
12503 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12504 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12508 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12515 if(t.execCall && t.execCall.call(this, values, parent)){
12519 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12525 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12526 parent = t.target ? values : parent;
12527 if(t.forCall && vs instanceof Array){
12529 for(var i = 0, len = vs.length; i < len; i++){
12531 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12533 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12535 //Roo.log(t.compiled);
12539 return buf.join('');
12542 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12547 return t.compiled.call(this, vs, parent);
12549 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12551 //Roo.log(t.compiled);
12559 applyTemplate : function(values){
12560 return this.master.compiled.call(this, values, {});
12561 //var s = this.subs;
12564 apply : function(){
12565 return this.applyTemplate.apply(this, arguments);
12570 Roo.DomTemplate.from = function(el){
12571 el = Roo.getDom(el);
12572 return new Roo.Domtemplate(el.value || el.innerHTML);
12575 * Ext JS Library 1.1.1
12576 * Copyright(c) 2006-2007, Ext JS, LLC.
12578 * Originally Released Under LGPL - original licence link has changed is not relivant.
12581 * <script type="text/javascript">
12585 * @class Roo.util.DelayedTask
12586 * Provides a convenient method of performing setTimeout where a new
12587 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12588 * You can use this class to buffer
12589 * the keypress events for a certain number of milliseconds, and perform only if they stop
12590 * for that amount of time.
12591 * @constructor The parameters to this constructor serve as defaults and are not required.
12592 * @param {Function} fn (optional) The default function to timeout
12593 * @param {Object} scope (optional) The default scope of that timeout
12594 * @param {Array} args (optional) The default Array of arguments
12596 Roo.util.DelayedTask = function(fn, scope, args){
12597 var id = null, d, t;
12599 var call = function(){
12600 var now = new Date().getTime();
12604 fn.apply(scope, args || []);
12608 * Cancels any pending timeout and queues a new one
12609 * @param {Number} delay The milliseconds to delay
12610 * @param {Function} newFn (optional) Overrides function passed to constructor
12611 * @param {Object} newScope (optional) Overrides scope passed to constructor
12612 * @param {Array} newArgs (optional) Overrides args passed to constructor
12614 this.delay = function(delay, newFn, newScope, newArgs){
12615 if(id && delay != d){
12619 t = new Date().getTime();
12621 scope = newScope || scope;
12622 args = newArgs || args;
12624 id = setInterval(call, d);
12629 * Cancel the last queued timeout
12631 this.cancel = function(){
12639 * Ext JS Library 1.1.1
12640 * Copyright(c) 2006-2007, Ext JS, LLC.
12642 * Originally Released Under LGPL - original licence link has changed is not relivant.
12645 * <script type="text/javascript">
12649 Roo.util.TaskRunner = function(interval){
12650 interval = interval || 10;
12651 var tasks = [], removeQueue = [];
12653 var running = false;
12655 var stopThread = function(){
12661 var startThread = function(){
12664 id = setInterval(runTasks, interval);
12668 var removeTask = function(task){
12669 removeQueue.push(task);
12675 var runTasks = function(){
12676 if(removeQueue.length > 0){
12677 for(var i = 0, len = removeQueue.length; i < len; i++){
12678 tasks.remove(removeQueue[i]);
12681 if(tasks.length < 1){
12686 var now = new Date().getTime();
12687 for(var i = 0, len = tasks.length; i < len; ++i){
12689 var itime = now - t.taskRunTime;
12690 if(t.interval <= itime){
12691 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12692 t.taskRunTime = now;
12693 if(rt === false || t.taskRunCount === t.repeat){
12698 if(t.duration && t.duration <= (now - t.taskStartTime)){
12705 * Queues a new task.
12706 * @param {Object} task
12708 this.start = function(task){
12710 task.taskStartTime = new Date().getTime();
12711 task.taskRunTime = 0;
12712 task.taskRunCount = 0;
12717 this.stop = function(task){
12722 this.stopAll = function(){
12724 for(var i = 0, len = tasks.length; i < len; i++){
12725 if(tasks[i].onStop){
12734 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12736 * Ext JS Library 1.1.1
12737 * Copyright(c) 2006-2007, Ext JS, LLC.
12739 * Originally Released Under LGPL - original licence link has changed is not relivant.
12742 * <script type="text/javascript">
12747 * @class Roo.util.MixedCollection
12748 * @extends Roo.util.Observable
12749 * A Collection class that maintains both numeric indexes and keys and exposes events.
12751 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12752 * collection (defaults to false)
12753 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12754 * and return the key value for that item. This is used when available to look up the key on items that
12755 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12756 * equivalent to providing an implementation for the {@link #getKey} method.
12758 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12766 * Fires when the collection is cleared.
12771 * Fires when an item is added to the collection.
12772 * @param {Number} index The index at which the item was added.
12773 * @param {Object} o The item added.
12774 * @param {String} key The key associated with the added item.
12779 * Fires when an item is replaced in the collection.
12780 * @param {String} key he key associated with the new added.
12781 * @param {Object} old The item being replaced.
12782 * @param {Object} new The new item.
12787 * Fires when an item is removed from the collection.
12788 * @param {Object} o The item being removed.
12789 * @param {String} key (optional) The key associated with the removed item.
12794 this.allowFunctions = allowFunctions === true;
12796 this.getKey = keyFn;
12798 Roo.util.MixedCollection.superclass.constructor.call(this);
12801 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12802 allowFunctions : false,
12805 * Adds an item to the collection.
12806 * @param {String} key The key to associate with the item
12807 * @param {Object} o The item to add.
12808 * @return {Object} The item added.
12810 add : function(key, o){
12811 if(arguments.length == 1){
12813 key = this.getKey(o);
12815 if(typeof key == "undefined" || key === null){
12817 this.items.push(o);
12818 this.keys.push(null);
12820 var old = this.map[key];
12822 return this.replace(key, o);
12825 this.items.push(o);
12827 this.keys.push(key);
12829 this.fireEvent("add", this.length-1, o, key);
12834 * MixedCollection has a generic way to fetch keys if you implement getKey.
12837 var mc = new Roo.util.MixedCollection();
12838 mc.add(someEl.dom.id, someEl);
12839 mc.add(otherEl.dom.id, otherEl);
12843 var mc = new Roo.util.MixedCollection();
12844 mc.getKey = function(el){
12850 // or via the constructor
12851 var mc = new Roo.util.MixedCollection(false, function(el){
12857 * @param o {Object} The item for which to find the key.
12858 * @return {Object} The key for the passed item.
12860 getKey : function(o){
12865 * Replaces an item in the collection.
12866 * @param {String} key The key associated with the item to replace, or the item to replace.
12867 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12868 * @return {Object} The new item.
12870 replace : function(key, o){
12871 if(arguments.length == 1){
12873 key = this.getKey(o);
12875 var old = this.item(key);
12876 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12877 return this.add(key, o);
12879 var index = this.indexOfKey(key);
12880 this.items[index] = o;
12882 this.fireEvent("replace", key, old, o);
12887 * Adds all elements of an Array or an Object to the collection.
12888 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12889 * an Array of values, each of which are added to the collection.
12891 addAll : function(objs){
12892 if(arguments.length > 1 || objs instanceof Array){
12893 var args = arguments.length > 1 ? arguments : objs;
12894 for(var i = 0, len = args.length; i < len; i++){
12898 for(var key in objs){
12899 if(this.allowFunctions || typeof objs[key] != "function"){
12900 this.add(key, objs[key]);
12907 * Executes the specified function once for every item in the collection, passing each
12908 * item as the first and only parameter. returning false from the function will stop the iteration.
12909 * @param {Function} fn The function to execute for each item.
12910 * @param {Object} scope (optional) The scope in which to execute the function.
12912 each : function(fn, scope){
12913 var items = [].concat(this.items); // each safe for removal
12914 for(var i = 0, len = items.length; i < len; i++){
12915 if(fn.call(scope || items[i], items[i], i, len) === false){
12922 * Executes the specified function once for every key in the collection, passing each
12923 * key, and its associated item as the first two parameters.
12924 * @param {Function} fn The function to execute for each item.
12925 * @param {Object} scope (optional) The scope in which to execute the function.
12927 eachKey : function(fn, scope){
12928 for(var i = 0, len = this.keys.length; i < len; i++){
12929 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12934 * Returns the first item in the collection which elicits a true return value from the
12935 * passed selection function.
12936 * @param {Function} fn The selection function to execute for each item.
12937 * @param {Object} scope (optional) The scope in which to execute the function.
12938 * @return {Object} The first item in the collection which returned true from the selection function.
12940 find : function(fn, scope){
12941 for(var i = 0, len = this.items.length; i < len; i++){
12942 if(fn.call(scope || window, this.items[i], this.keys[i])){
12943 return this.items[i];
12950 * Inserts an item at the specified index in the collection.
12951 * @param {Number} index The index to insert the item at.
12952 * @param {String} key The key to associate with the new item, or the item itself.
12953 * @param {Object} o (optional) If the second parameter was a key, the new item.
12954 * @return {Object} The item inserted.
12956 insert : function(index, key, o){
12957 if(arguments.length == 2){
12959 key = this.getKey(o);
12961 if(index >= this.length){
12962 return this.add(key, o);
12965 this.items.splice(index, 0, o);
12966 if(typeof key != "undefined" && key != null){
12969 this.keys.splice(index, 0, key);
12970 this.fireEvent("add", index, o, key);
12975 * Removed an item from the collection.
12976 * @param {Object} o The item to remove.
12977 * @return {Object} The item removed.
12979 remove : function(o){
12980 return this.removeAt(this.indexOf(o));
12984 * Remove an item from a specified index in the collection.
12985 * @param {Number} index The index within the collection of the item to remove.
12987 removeAt : function(index){
12988 if(index < this.length && index >= 0){
12990 var o = this.items[index];
12991 this.items.splice(index, 1);
12992 var key = this.keys[index];
12993 if(typeof key != "undefined"){
12994 delete this.map[key];
12996 this.keys.splice(index, 1);
12997 this.fireEvent("remove", o, key);
13002 * Removed an item associated with the passed key fom the collection.
13003 * @param {String} key The key of the item to remove.
13005 removeKey : function(key){
13006 return this.removeAt(this.indexOfKey(key));
13010 * Returns the number of items in the collection.
13011 * @return {Number} the number of items in the collection.
13013 getCount : function(){
13014 return this.length;
13018 * Returns index within the collection of the passed Object.
13019 * @param {Object} o The item to find the index of.
13020 * @return {Number} index of the item.
13022 indexOf : function(o){
13023 if(!this.items.indexOf){
13024 for(var i = 0, len = this.items.length; i < len; i++){
13025 if(this.items[i] == o) return i;
13029 return this.items.indexOf(o);
13034 * Returns index within the collection of the passed key.
13035 * @param {String} key The key to find the index of.
13036 * @return {Number} index of the key.
13038 indexOfKey : function(key){
13039 if(!this.keys.indexOf){
13040 for(var i = 0, len = this.keys.length; i < len; i++){
13041 if(this.keys[i] == key) return i;
13045 return this.keys.indexOf(key);
13050 * Returns the item associated with the passed key OR index. Key has priority over index.
13051 * @param {String/Number} key The key or index of the item.
13052 * @return {Object} The item associated with the passed key.
13054 item : function(key){
13055 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13056 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13060 * Returns the item at the specified index.
13061 * @param {Number} index The index of the item.
13064 itemAt : function(index){
13065 return this.items[index];
13069 * Returns the item associated with the passed key.
13070 * @param {String/Number} key The key of the item.
13071 * @return {Object} The item associated with the passed key.
13073 key : function(key){
13074 return this.map[key];
13078 * Returns true if the collection contains the passed Object as an item.
13079 * @param {Object} o The Object to look for in the collection.
13080 * @return {Boolean} True if the collection contains the Object as an item.
13082 contains : function(o){
13083 return this.indexOf(o) != -1;
13087 * Returns true if the collection contains the passed Object as a key.
13088 * @param {String} key The key to look for in the collection.
13089 * @return {Boolean} True if the collection contains the Object as a key.
13091 containsKey : function(key){
13092 return typeof this.map[key] != "undefined";
13096 * Removes all items from the collection.
13098 clear : function(){
13103 this.fireEvent("clear");
13107 * Returns the first item in the collection.
13108 * @return {Object} the first item in the collection..
13110 first : function(){
13111 return this.items[0];
13115 * Returns the last item in the collection.
13116 * @return {Object} the last item in the collection..
13119 return this.items[this.length-1];
13122 _sort : function(property, dir, fn){
13123 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13124 fn = fn || function(a, b){
13127 var c = [], k = this.keys, items = this.items;
13128 for(var i = 0, len = items.length; i < len; i++){
13129 c[c.length] = {key: k[i], value: items[i], index: i};
13131 c.sort(function(a, b){
13132 var v = fn(a[property], b[property]) * dsc;
13134 v = (a.index < b.index ? -1 : 1);
13138 for(var i = 0, len = c.length; i < len; i++){
13139 items[i] = c[i].value;
13142 this.fireEvent("sort", this);
13146 * Sorts this collection with the passed comparison function
13147 * @param {String} direction (optional) "ASC" or "DESC"
13148 * @param {Function} fn (optional) comparison function
13150 sort : function(dir, fn){
13151 this._sort("value", dir, fn);
13155 * Sorts this collection by keys
13156 * @param {String} direction (optional) "ASC" or "DESC"
13157 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13159 keySort : function(dir, fn){
13160 this._sort("key", dir, fn || function(a, b){
13161 return String(a).toUpperCase()-String(b).toUpperCase();
13166 * Returns a range of items in this collection
13167 * @param {Number} startIndex (optional) defaults to 0
13168 * @param {Number} endIndex (optional) default to the last item
13169 * @return {Array} An array of items
13171 getRange : function(start, end){
13172 var items = this.items;
13173 if(items.length < 1){
13176 start = start || 0;
13177 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13180 for(var i = start; i <= end; i++) {
13181 r[r.length] = items[i];
13184 for(var i = start; i >= end; i--) {
13185 r[r.length] = items[i];
13192 * Filter the <i>objects</i> in this collection by a specific property.
13193 * Returns a new collection that has been filtered.
13194 * @param {String} property A property on your objects
13195 * @param {String/RegExp} value Either string that the property values
13196 * should start with or a RegExp to test against the property
13197 * @return {MixedCollection} The new filtered collection
13199 filter : function(property, value){
13200 if(!value.exec){ // not a regex
13201 value = String(value);
13202 if(value.length == 0){
13203 return this.clone();
13205 value = new RegExp("^" + Roo.escapeRe(value), "i");
13207 return this.filterBy(function(o){
13208 return o && value.test(o[property]);
13213 * Filter by a function. * Returns a new collection that has been filtered.
13214 * The passed function will be called with each
13215 * object in the collection. If the function returns true, the value is included
13216 * otherwise it is filtered.
13217 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13218 * @param {Object} scope (optional) The scope of the function (defaults to this)
13219 * @return {MixedCollection} The new filtered collection
13221 filterBy : function(fn, scope){
13222 var r = new Roo.util.MixedCollection();
13223 r.getKey = this.getKey;
13224 var k = this.keys, it = this.items;
13225 for(var i = 0, len = it.length; i < len; i++){
13226 if(fn.call(scope||this, it[i], k[i])){
13227 r.add(k[i], it[i]);
13234 * Creates a duplicate of this collection
13235 * @return {MixedCollection}
13237 clone : function(){
13238 var r = new Roo.util.MixedCollection();
13239 var k = this.keys, it = this.items;
13240 for(var i = 0, len = it.length; i < len; i++){
13241 r.add(k[i], it[i]);
13243 r.getKey = this.getKey;
13248 * Returns the item associated with the passed key or index.
13250 * @param {String/Number} key The key or index of the item.
13251 * @return {Object} The item associated with the passed key.
13253 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13255 * Ext JS Library 1.1.1
13256 * Copyright(c) 2006-2007, Ext JS, LLC.
13258 * Originally Released Under LGPL - original licence link has changed is not relivant.
13261 * <script type="text/javascript">
13264 * @class Roo.util.JSON
13265 * Modified version of Douglas Crockford"s json.js that doesn"t
13266 * mess with the Object prototype
13267 * http://www.json.org/js.html
13270 Roo.util.JSON = new (function(){
13271 var useHasOwn = {}.hasOwnProperty ? true : false;
13273 // crashes Safari in some instances
13274 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13276 var pad = function(n) {
13277 return n < 10 ? "0" + n : n;
13290 var encodeString = function(s){
13291 if (/["\\\x00-\x1f]/.test(s)) {
13292 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13297 c = b.charCodeAt();
13299 Math.floor(c / 16).toString(16) +
13300 (c % 16).toString(16);
13303 return '"' + s + '"';
13306 var encodeArray = function(o){
13307 var a = ["["], b, i, l = o.length, v;
13308 for (i = 0; i < l; i += 1) {
13310 switch (typeof v) {
13319 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13327 var encodeDate = function(o){
13328 return '"' + o.getFullYear() + "-" +
13329 pad(o.getMonth() + 1) + "-" +
13330 pad(o.getDate()) + "T" +
13331 pad(o.getHours()) + ":" +
13332 pad(o.getMinutes()) + ":" +
13333 pad(o.getSeconds()) + '"';
13337 * Encodes an Object, Array or other value
13338 * @param {Mixed} o The variable to encode
13339 * @return {String} The JSON string
13341 this.encode = function(o)
13343 // should this be extended to fully wrap stringify..
13345 if(typeof o == "undefined" || o === null){
13347 }else if(o instanceof Array){
13348 return encodeArray(o);
13349 }else if(o instanceof Date){
13350 return encodeDate(o);
13351 }else if(typeof o == "string"){
13352 return encodeString(o);
13353 }else if(typeof o == "number"){
13354 return isFinite(o) ? String(o) : "null";
13355 }else if(typeof o == "boolean"){
13358 var a = ["{"], b, i, v;
13360 if(!useHasOwn || o.hasOwnProperty(i)) {
13362 switch (typeof v) {
13371 a.push(this.encode(i), ":",
13372 v === null ? "null" : this.encode(v));
13383 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13384 * @param {String} json The JSON string
13385 * @return {Object} The resulting object
13387 this.decode = function(json){
13389 return /** eval:var:json */ eval("(" + json + ')');
13393 * Shorthand for {@link Roo.util.JSON#encode}
13394 * @member Roo encode
13396 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13398 * Shorthand for {@link Roo.util.JSON#decode}
13399 * @member Roo decode
13401 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13404 * Ext JS Library 1.1.1
13405 * Copyright(c) 2006-2007, Ext JS, LLC.
13407 * Originally Released Under LGPL - original licence link has changed is not relivant.
13410 * <script type="text/javascript">
13414 * @class Roo.util.Format
13415 * Reusable data formatting functions
13418 Roo.util.Format = function(){
13419 var trimRe = /^\s+|\s+$/g;
13422 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13423 * @param {String} value The string to truncate
13424 * @param {Number} length The maximum length to allow before truncating
13425 * @return {String} The converted text
13427 ellipsis : function(value, len){
13428 if(value && value.length > len){
13429 return value.substr(0, len-3)+"...";
13435 * Checks a reference and converts it to empty string if it is undefined
13436 * @param {Mixed} value Reference to check
13437 * @return {Mixed} Empty string if converted, otherwise the original value
13439 undef : function(value){
13440 return typeof value != "undefined" ? value : "";
13444 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13445 * @param {String} value The string to encode
13446 * @return {String} The encoded text
13448 htmlEncode : function(value){
13449 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13453 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13454 * @param {String} value The string to decode
13455 * @return {String} The decoded text
13457 htmlDecode : function(value){
13458 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13462 * Trims any whitespace from either side of a string
13463 * @param {String} value The text to trim
13464 * @return {String} The trimmed text
13466 trim : function(value){
13467 return String(value).replace(trimRe, "");
13471 * Returns a substring from within an original string
13472 * @param {String} value The original text
13473 * @param {Number} start The start index of the substring
13474 * @param {Number} length The length of the substring
13475 * @return {String} The substring
13477 substr : function(value, start, length){
13478 return String(value).substr(start, length);
13482 * Converts a string to all lower case letters
13483 * @param {String} value The text to convert
13484 * @return {String} The converted text
13486 lowercase : function(value){
13487 return String(value).toLowerCase();
13491 * Converts a string to all upper case letters
13492 * @param {String} value The text to convert
13493 * @return {String} The converted text
13495 uppercase : function(value){
13496 return String(value).toUpperCase();
13500 * Converts the first character only of a string to upper case
13501 * @param {String} value The text to convert
13502 * @return {String} The converted text
13504 capitalize : function(value){
13505 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13509 call : function(value, fn){
13510 if(arguments.length > 2){
13511 var args = Array.prototype.slice.call(arguments, 2);
13512 args.unshift(value);
13514 return /** eval:var:value */ eval(fn).apply(window, args);
13516 /** eval:var:value */
13517 return /** eval:var:value */ eval(fn).call(window, value);
13523 * safer version of Math.toFixed..??/
13524 * @param {Number/String} value The numeric value to format
13525 * @param {Number/String} value Decimal places
13526 * @return {String} The formatted currency string
13528 toFixed : function(v, n)
13530 // why not use to fixed - precision is buggered???
13532 return Math.round(v-0);
13534 var fact = Math.pow(10,n+1);
13535 v = (Math.round((v-0)*fact))/fact;
13536 var z = (''+fact).substring(2);
13537 if (v == Math.floor(v)) {
13538 return Math.floor(v) + '.' + z;
13541 // now just padd decimals..
13542 var ps = String(v).split('.');
13543 var fd = (ps[1] + z);
13544 var r = fd.substring(0,n);
13545 var rm = fd.substring(n);
13547 return ps[0] + '.' + r;
13549 r*=1; // turn it into a number;
13551 if (String(r).length != n) {
13554 r = String(r).substring(1); // chop the end off.
13557 return ps[0] + '.' + r;
13562 * Format a number as US currency
13563 * @param {Number/String} value The numeric value to format
13564 * @return {String} The formatted currency string
13566 usMoney : function(v){
13567 return '$' + Roo.util.Format.number(v);
13572 * eventually this should probably emulate php's number_format
13573 * @param {Number/String} value The numeric value to format
13574 * @param {Number} decimals number of decimal places
13575 * @return {String} The formatted currency string
13577 number : function(v,decimals)
13579 // multiply and round.
13580 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13581 var mul = Math.pow(10, decimals);
13582 var zero = String(mul).substring(1);
13583 v = (Math.round((v-0)*mul))/mul;
13585 // if it's '0' number.. then
13587 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13589 var ps = v.split('.');
13593 var r = /(\d+)(\d{3})/;
13595 while (r.test(whole)) {
13596 whole = whole.replace(r, '$1' + ',' + '$2');
13602 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13603 // does not have decimals
13604 (decimals ? ('.' + zero) : '');
13607 return whole + sub ;
13611 * Parse a value into a formatted date using the specified format pattern.
13612 * @param {Mixed} value The value to format
13613 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13614 * @return {String} The formatted date string
13616 date : function(v, format){
13620 if(!(v instanceof Date)){
13621 v = new Date(Date.parse(v));
13623 return v.dateFormat(format || Roo.util.Format.defaults.date);
13627 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13628 * @param {String} format Any valid date format string
13629 * @return {Function} The date formatting function
13631 dateRenderer : function(format){
13632 return function(v){
13633 return Roo.util.Format.date(v, format);
13638 stripTagsRE : /<\/?[^>]+>/gi,
13641 * Strips all HTML tags
13642 * @param {Mixed} value The text from which to strip tags
13643 * @return {String} The stripped text
13645 stripTags : function(v){
13646 return !v ? v : String(v).replace(this.stripTagsRE, "");
13650 Roo.util.Format.defaults = {
13654 * Ext JS Library 1.1.1
13655 * Copyright(c) 2006-2007, Ext JS, LLC.
13657 * Originally Released Under LGPL - original licence link has changed is not relivant.
13660 * <script type="text/javascript">
13667 * @class Roo.MasterTemplate
13668 * @extends Roo.Template
13669 * Provides a template that can have child templates. The syntax is:
13671 var t = new Roo.MasterTemplate(
13672 '<select name="{name}">',
13673 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13676 t.add('options', {value: 'foo', text: 'bar'});
13677 // or you can add multiple child elements in one shot
13678 t.addAll('options', [
13679 {value: 'foo', text: 'bar'},
13680 {value: 'foo2', text: 'bar2'},
13681 {value: 'foo3', text: 'bar3'}
13683 // then append, applying the master template values
13684 t.append('my-form', {name: 'my-select'});
13686 * A name attribute for the child template is not required if you have only one child
13687 * template or you want to refer to them by index.
13689 Roo.MasterTemplate = function(){
13690 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13691 this.originalHtml = this.html;
13693 var m, re = this.subTemplateRe;
13696 while(m = re.exec(this.html)){
13697 var name = m[1], content = m[2];
13702 tpl : new Roo.Template(content)
13705 st[name] = st[subIndex];
13707 st[subIndex].tpl.compile();
13708 st[subIndex].tpl.call = this.call.createDelegate(this);
13711 this.subCount = subIndex;
13714 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13716 * The regular expression used to match sub templates
13720 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13723 * Applies the passed values to a child template.
13724 * @param {String/Number} name (optional) The name or index of the child template
13725 * @param {Array/Object} values The values to be applied to the template
13726 * @return {MasterTemplate} this
13728 add : function(name, values){
13729 if(arguments.length == 1){
13730 values = arguments[0];
13733 var s = this.subs[name];
13734 s.buffer[s.buffer.length] = s.tpl.apply(values);
13739 * Applies all the passed values to a child template.
13740 * @param {String/Number} name (optional) The name or index of the child template
13741 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13742 * @param {Boolean} reset (optional) True to reset the template first
13743 * @return {MasterTemplate} this
13745 fill : function(name, values, reset){
13747 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13755 for(var i = 0, len = values.length; i < len; i++){
13756 this.add(name, values[i]);
13762 * Resets the template for reuse
13763 * @return {MasterTemplate} this
13765 reset : function(){
13767 for(var i = 0; i < this.subCount; i++){
13773 applyTemplate : function(values){
13775 var replaceIndex = -1;
13776 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13777 return s[++replaceIndex].buffer.join("");
13779 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13782 apply : function(){
13783 return this.applyTemplate.apply(this, arguments);
13786 compile : function(){return this;}
13790 * Alias for fill().
13793 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13795 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13796 * var tpl = Roo.MasterTemplate.from('element-id');
13797 * @param {String/HTMLElement} el
13798 * @param {Object} config
13801 Roo.MasterTemplate.from = function(el, config){
13802 el = Roo.getDom(el);
13803 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13806 * Ext JS Library 1.1.1
13807 * Copyright(c) 2006-2007, Ext JS, LLC.
13809 * Originally Released Under LGPL - original licence link has changed is not relivant.
13812 * <script type="text/javascript">
13817 * @class Roo.util.CSS
13818 * Utility class for manipulating CSS rules
13821 Roo.util.CSS = function(){
13823 var doc = document;
13825 var camelRe = /(-[a-z])/gi;
13826 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13830 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13831 * tag and appended to the HEAD of the document.
13832 * @param {String|Object} cssText The text containing the css rules
13833 * @param {String} id An id to add to the stylesheet for later removal
13834 * @return {StyleSheet}
13836 createStyleSheet : function(cssText, id){
13838 var head = doc.getElementsByTagName("head")[0];
13839 var nrules = doc.createElement("style");
13840 nrules.setAttribute("type", "text/css");
13842 nrules.setAttribute("id", id);
13844 if (typeof(cssText) != 'string') {
13845 // support object maps..
13846 // not sure if this a good idea..
13847 // perhaps it should be merged with the general css handling
13848 // and handle js style props.
13849 var cssTextNew = [];
13850 for(var n in cssText) {
13852 for(var k in cssText[n]) {
13853 citems.push( k + ' : ' +cssText[n][k] + ';' );
13855 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13858 cssText = cssTextNew.join("\n");
13864 head.appendChild(nrules);
13865 ss = nrules.styleSheet;
13866 ss.cssText = cssText;
13869 nrules.appendChild(doc.createTextNode(cssText));
13871 nrules.cssText = cssText;
13873 head.appendChild(nrules);
13874 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13876 this.cacheStyleSheet(ss);
13881 * Removes a style or link tag by id
13882 * @param {String} id The id of the tag
13884 removeStyleSheet : function(id){
13885 var existing = doc.getElementById(id);
13887 existing.parentNode.removeChild(existing);
13892 * Dynamically swaps an existing stylesheet reference for a new one
13893 * @param {String} id The id of an existing link tag to remove
13894 * @param {String} url The href of the new stylesheet to include
13896 swapStyleSheet : function(id, url){
13897 this.removeStyleSheet(id);
13898 var ss = doc.createElement("link");
13899 ss.setAttribute("rel", "stylesheet");
13900 ss.setAttribute("type", "text/css");
13901 ss.setAttribute("id", id);
13902 ss.setAttribute("href", url);
13903 doc.getElementsByTagName("head")[0].appendChild(ss);
13907 * Refresh the rule cache if you have dynamically added stylesheets
13908 * @return {Object} An object (hash) of rules indexed by selector
13910 refreshCache : function(){
13911 return this.getRules(true);
13915 cacheStyleSheet : function(stylesheet){
13919 try{// try catch for cross domain access issue
13920 var ssRules = stylesheet.cssRules || stylesheet.rules;
13921 for(var j = ssRules.length-1; j >= 0; --j){
13922 rules[ssRules[j].selectorText] = ssRules[j];
13928 * Gets all css rules for the document
13929 * @param {Boolean} refreshCache true to refresh the internal cache
13930 * @return {Object} An object (hash) of rules indexed by selector
13932 getRules : function(refreshCache){
13933 if(rules == null || refreshCache){
13935 var ds = doc.styleSheets;
13936 for(var i =0, len = ds.length; i < len; i++){
13938 this.cacheStyleSheet(ds[i]);
13946 * Gets an an individual CSS rule by selector(s)
13947 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13948 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13949 * @return {CSSRule} The CSS rule or null if one is not found
13951 getRule : function(selector, refreshCache){
13952 var rs = this.getRules(refreshCache);
13953 if(!(selector instanceof Array)){
13954 return rs[selector];
13956 for(var i = 0; i < selector.length; i++){
13957 if(rs[selector[i]]){
13958 return rs[selector[i]];
13966 * Updates a rule property
13967 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13968 * @param {String} property The css property
13969 * @param {String} value The new value for the property
13970 * @return {Boolean} true If a rule was found and updated
13972 updateRule : function(selector, property, value){
13973 if(!(selector instanceof Array)){
13974 var rule = this.getRule(selector);
13976 rule.style[property.replace(camelRe, camelFn)] = value;
13980 for(var i = 0; i < selector.length; i++){
13981 if(this.updateRule(selector[i], property, value)){
13991 * Ext JS Library 1.1.1
13992 * Copyright(c) 2006-2007, Ext JS, LLC.
13994 * Originally Released Under LGPL - original licence link has changed is not relivant.
13997 * <script type="text/javascript">
14003 * @class Roo.util.ClickRepeater
14004 * @extends Roo.util.Observable
14006 * A wrapper class which can be applied to any element. Fires a "click" event while the
14007 * mouse is pressed. The interval between firings may be specified in the config but
14008 * defaults to 10 milliseconds.
14010 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14012 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14013 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14014 * Similar to an autorepeat key delay.
14015 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14016 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14017 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14018 * "interval" and "delay" are ignored. "immediate" is honored.
14019 * @cfg {Boolean} preventDefault True to prevent the default click event
14020 * @cfg {Boolean} stopDefault True to stop the default click event
14023 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14024 * 2007-02-02 jvs Renamed to ClickRepeater
14025 * 2007-02-03 jvs Modifications for FF Mac and Safari
14028 * @param {String/HTMLElement/Element} el The element to listen on
14029 * @param {Object} config
14031 Roo.util.ClickRepeater = function(el, config)
14033 this.el = Roo.get(el);
14034 this.el.unselectable();
14036 Roo.apply(this, config);
14041 * Fires when the mouse button is depressed.
14042 * @param {Roo.util.ClickRepeater} this
14044 "mousedown" : true,
14047 * Fires on a specified interval during the time the element is pressed.
14048 * @param {Roo.util.ClickRepeater} this
14053 * Fires when the mouse key is released.
14054 * @param {Roo.util.ClickRepeater} this
14059 this.el.on("mousedown", this.handleMouseDown, this);
14060 if(this.preventDefault || this.stopDefault){
14061 this.el.on("click", function(e){
14062 if(this.preventDefault){
14063 e.preventDefault();
14065 if(this.stopDefault){
14071 // allow inline handler
14073 this.on("click", this.handler, this.scope || this);
14076 Roo.util.ClickRepeater.superclass.constructor.call(this);
14079 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14082 preventDefault : true,
14083 stopDefault : false,
14087 handleMouseDown : function(){
14088 clearTimeout(this.timer);
14090 if(this.pressClass){
14091 this.el.addClass(this.pressClass);
14093 this.mousedownTime = new Date();
14095 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14096 this.el.on("mouseout", this.handleMouseOut, this);
14098 this.fireEvent("mousedown", this);
14099 this.fireEvent("click", this);
14101 this.timer = this.click.defer(this.delay || this.interval, this);
14105 click : function(){
14106 this.fireEvent("click", this);
14107 this.timer = this.click.defer(this.getInterval(), this);
14111 getInterval: function(){
14112 if(!this.accelerate){
14113 return this.interval;
14115 var pressTime = this.mousedownTime.getElapsed();
14116 if(pressTime < 500){
14118 }else if(pressTime < 1700){
14120 }else if(pressTime < 2600){
14122 }else if(pressTime < 3500){
14124 }else if(pressTime < 4400){
14126 }else if(pressTime < 5300){
14128 }else if(pressTime < 6200){
14136 handleMouseOut : function(){
14137 clearTimeout(this.timer);
14138 if(this.pressClass){
14139 this.el.removeClass(this.pressClass);
14141 this.el.on("mouseover", this.handleMouseReturn, this);
14145 handleMouseReturn : function(){
14146 this.el.un("mouseover", this.handleMouseReturn);
14147 if(this.pressClass){
14148 this.el.addClass(this.pressClass);
14154 handleMouseUp : function(){
14155 clearTimeout(this.timer);
14156 this.el.un("mouseover", this.handleMouseReturn);
14157 this.el.un("mouseout", this.handleMouseOut);
14158 Roo.get(document).un("mouseup", this.handleMouseUp);
14159 this.el.removeClass(this.pressClass);
14160 this.fireEvent("mouseup", this);
14164 * Ext JS Library 1.1.1
14165 * Copyright(c) 2006-2007, Ext JS, LLC.
14167 * Originally Released Under LGPL - original licence link has changed is not relivant.
14170 * <script type="text/javascript">
14175 * @class Roo.KeyNav
14176 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14177 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14178 * way to implement custom navigation schemes for any UI component.</p>
14179 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14180 * pageUp, pageDown, del, home, end. Usage:</p>
14182 var nav = new Roo.KeyNav("my-element", {
14183 "left" : function(e){
14184 this.moveLeft(e.ctrlKey);
14186 "right" : function(e){
14187 this.moveRight(e.ctrlKey);
14189 "enter" : function(e){
14196 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14197 * @param {Object} config The config
14199 Roo.KeyNav = function(el, config){
14200 this.el = Roo.get(el);
14201 Roo.apply(this, config);
14202 if(!this.disabled){
14203 this.disabled = true;
14208 Roo.KeyNav.prototype = {
14210 * @cfg {Boolean} disabled
14211 * True to disable this KeyNav instance (defaults to false)
14215 * @cfg {String} defaultEventAction
14216 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14217 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14218 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14220 defaultEventAction: "stopEvent",
14222 * @cfg {Boolean} forceKeyDown
14223 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14224 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14225 * handle keydown instead of keypress.
14227 forceKeyDown : false,
14230 prepareEvent : function(e){
14231 var k = e.getKey();
14232 var h = this.keyToHandler[k];
14233 //if(h && this[h]){
14234 // e.stopPropagation();
14236 if(Roo.isSafari && h && k >= 37 && k <= 40){
14242 relay : function(e){
14243 var k = e.getKey();
14244 var h = this.keyToHandler[k];
14246 if(this.doRelay(e, this[h], h) !== true){
14247 e[this.defaultEventAction]();
14253 doRelay : function(e, h, hname){
14254 return h.call(this.scope || this, e);
14257 // possible handlers
14271 // quick lookup hash
14288 * Enable this KeyNav
14290 enable: function(){
14292 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14293 // the EventObject will normalize Safari automatically
14294 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14295 this.el.on("keydown", this.relay, this);
14297 this.el.on("keydown", this.prepareEvent, this);
14298 this.el.on("keypress", this.relay, this);
14300 this.disabled = false;
14305 * Disable this KeyNav
14307 disable: function(){
14308 if(!this.disabled){
14309 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14310 this.el.un("keydown", this.relay);
14312 this.el.un("keydown", this.prepareEvent);
14313 this.el.un("keypress", this.relay);
14315 this.disabled = true;
14320 * Ext JS Library 1.1.1
14321 * Copyright(c) 2006-2007, Ext JS, LLC.
14323 * Originally Released Under LGPL - original licence link has changed is not relivant.
14326 * <script type="text/javascript">
14331 * @class Roo.KeyMap
14332 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14333 * The constructor accepts the same config object as defined by {@link #addBinding}.
14334 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14335 * combination it will call the function with this signature (if the match is a multi-key
14336 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14337 * A KeyMap can also handle a string representation of keys.<br />
14340 // map one key by key code
14341 var map = new Roo.KeyMap("my-element", {
14342 key: 13, // or Roo.EventObject.ENTER
14347 // map multiple keys to one action by string
14348 var map = new Roo.KeyMap("my-element", {
14354 // map multiple keys to multiple actions by strings and array of codes
14355 var map = new Roo.KeyMap("my-element", [
14358 fn: function(){ alert("Return was pressed"); }
14361 fn: function(){ alert('a, b or c was pressed'); }
14366 fn: function(){ alert('Control + shift + tab was pressed.'); }
14370 * <b>Note: A KeyMap starts enabled</b>
14372 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14373 * @param {Object} config The config (see {@link #addBinding})
14374 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14376 Roo.KeyMap = function(el, config, eventName){
14377 this.el = Roo.get(el);
14378 this.eventName = eventName || "keydown";
14379 this.bindings = [];
14381 this.addBinding(config);
14386 Roo.KeyMap.prototype = {
14388 * True to stop the event from bubbling and prevent the default browser action if the
14389 * key was handled by the KeyMap (defaults to false)
14395 * Add a new binding to this KeyMap. The following config object properties are supported:
14397 Property Type Description
14398 ---------- --------------- ----------------------------------------------------------------------
14399 key String/Array A single keycode or an array of keycodes to handle
14400 shift Boolean True to handle key only when shift is pressed (defaults to false)
14401 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14402 alt Boolean True to handle key only when alt is pressed (defaults to false)
14403 fn Function The function to call when KeyMap finds the expected key combination
14404 scope Object The scope of the callback function
14410 var map = new Roo.KeyMap(document, {
14411 key: Roo.EventObject.ENTER,
14416 //Add a new binding to the existing KeyMap later
14424 * @param {Object/Array} config A single KeyMap config or an array of configs
14426 addBinding : function(config){
14427 if(config instanceof Array){
14428 for(var i = 0, len = config.length; i < len; i++){
14429 this.addBinding(config[i]);
14433 var keyCode = config.key,
14434 shift = config.shift,
14435 ctrl = config.ctrl,
14438 scope = config.scope;
14439 if(typeof keyCode == "string"){
14441 var keyString = keyCode.toUpperCase();
14442 for(var j = 0, len = keyString.length; j < len; j++){
14443 ks.push(keyString.charCodeAt(j));
14447 var keyArray = keyCode instanceof Array;
14448 var handler = function(e){
14449 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14450 var k = e.getKey();
14452 for(var i = 0, len = keyCode.length; i < len; i++){
14453 if(keyCode[i] == k){
14454 if(this.stopEvent){
14457 fn.call(scope || window, k, e);
14463 if(this.stopEvent){
14466 fn.call(scope || window, k, e);
14471 this.bindings.push(handler);
14475 * Shorthand for adding a single key listener
14476 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14477 * following options:
14478 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14479 * @param {Function} fn The function to call
14480 * @param {Object} scope (optional) The scope of the function
14482 on : function(key, fn, scope){
14483 var keyCode, shift, ctrl, alt;
14484 if(typeof key == "object" && !(key instanceof Array)){
14503 handleKeyDown : function(e){
14504 if(this.enabled){ //just in case
14505 var b = this.bindings;
14506 for(var i = 0, len = b.length; i < len; i++){
14507 b[i].call(this, e);
14513 * Returns true if this KeyMap is enabled
14514 * @return {Boolean}
14516 isEnabled : function(){
14517 return this.enabled;
14521 * Enables this KeyMap
14523 enable: function(){
14525 this.el.on(this.eventName, this.handleKeyDown, this);
14526 this.enabled = true;
14531 * Disable this KeyMap
14533 disable: function(){
14535 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14536 this.enabled = false;
14541 * Ext JS Library 1.1.1
14542 * Copyright(c) 2006-2007, Ext JS, LLC.
14544 * Originally Released Under LGPL - original licence link has changed is not relivant.
14547 * <script type="text/javascript">
14552 * @class Roo.util.TextMetrics
14553 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14554 * wide, in pixels, a given block of text will be.
14557 Roo.util.TextMetrics = function(){
14561 * Measures the size of the specified text
14562 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14563 * that can affect the size of the rendered text
14564 * @param {String} text The text to measure
14565 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14566 * in order to accurately measure the text height
14567 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14569 measure : function(el, text, fixedWidth){
14571 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14574 shared.setFixedWidth(fixedWidth || 'auto');
14575 return shared.getSize(text);
14579 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14580 * the overhead of multiple calls to initialize the style properties on each measurement.
14581 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14582 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14583 * in order to accurately measure the text height
14584 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14586 createInstance : function(el, fixedWidth){
14587 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14594 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14595 var ml = new Roo.Element(document.createElement('div'));
14596 document.body.appendChild(ml.dom);
14597 ml.position('absolute');
14598 ml.setLeftTop(-1000, -1000);
14602 ml.setWidth(fixedWidth);
14607 * Returns the size of the specified text based on the internal element's style and width properties
14608 * @memberOf Roo.util.TextMetrics.Instance#
14609 * @param {String} text The text to measure
14610 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14612 getSize : function(text){
14614 var s = ml.getSize();
14620 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14621 * that can affect the size of the rendered text
14622 * @memberOf Roo.util.TextMetrics.Instance#
14623 * @param {String/HTMLElement} el The element, dom node or id
14625 bind : function(el){
14627 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14632 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14633 * to set a fixed width in order to accurately measure the text height.
14634 * @memberOf Roo.util.TextMetrics.Instance#
14635 * @param {Number} width The width to set on the element
14637 setFixedWidth : function(width){
14638 ml.setWidth(width);
14642 * Returns the measured width of the specified text
14643 * @memberOf Roo.util.TextMetrics.Instance#
14644 * @param {String} text The text to measure
14645 * @return {Number} width The width in pixels
14647 getWidth : function(text){
14648 ml.dom.style.width = 'auto';
14649 return this.getSize(text).width;
14653 * Returns the measured height of the specified text. For multiline text, be sure to call
14654 * {@link #setFixedWidth} if necessary.
14655 * @memberOf Roo.util.TextMetrics.Instance#
14656 * @param {String} text The text to measure
14657 * @return {Number} height The height in pixels
14659 getHeight : function(text){
14660 return this.getSize(text).height;
14664 instance.bind(bindTo);
14669 // backwards compat
14670 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14672 * Ext JS Library 1.1.1
14673 * Copyright(c) 2006-2007, Ext JS, LLC.
14675 * Originally Released Under LGPL - original licence link has changed is not relivant.
14678 * <script type="text/javascript">
14682 * @class Roo.state.Provider
14683 * Abstract base class for state provider implementations. This class provides methods
14684 * for encoding and decoding <b>typed</b> variables including dates and defines the
14685 * Provider interface.
14687 Roo.state.Provider = function(){
14689 * @event statechange
14690 * Fires when a state change occurs.
14691 * @param {Provider} this This state provider
14692 * @param {String} key The state key which was changed
14693 * @param {String} value The encoded value for the state
14696 "statechange": true
14699 Roo.state.Provider.superclass.constructor.call(this);
14701 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14703 * Returns the current value for a key
14704 * @param {String} name The key name
14705 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14706 * @return {Mixed} The state data
14708 get : function(name, defaultValue){
14709 return typeof this.state[name] == "undefined" ?
14710 defaultValue : this.state[name];
14714 * Clears a value from the state
14715 * @param {String} name The key name
14717 clear : function(name){
14718 delete this.state[name];
14719 this.fireEvent("statechange", this, name, null);
14723 * Sets the value for a key
14724 * @param {String} name The key name
14725 * @param {Mixed} value The value to set
14727 set : function(name, value){
14728 this.state[name] = value;
14729 this.fireEvent("statechange", this, name, value);
14733 * Decodes a string previously encoded with {@link #encodeValue}.
14734 * @param {String} value The value to decode
14735 * @return {Mixed} The decoded value
14737 decodeValue : function(cookie){
14738 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14739 var matches = re.exec(unescape(cookie));
14740 if(!matches || !matches[1]) return; // non state cookie
14741 var type = matches[1];
14742 var v = matches[2];
14745 return parseFloat(v);
14747 return new Date(Date.parse(v));
14752 var values = v.split("^");
14753 for(var i = 0, len = values.length; i < len; i++){
14754 all.push(this.decodeValue(values[i]));
14759 var values = v.split("^");
14760 for(var i = 0, len = values.length; i < len; i++){
14761 var kv = values[i].split("=");
14762 all[kv[0]] = this.decodeValue(kv[1]);
14771 * Encodes a value including type information. Decode with {@link #decodeValue}.
14772 * @param {Mixed} value The value to encode
14773 * @return {String} The encoded value
14775 encodeValue : function(v){
14777 if(typeof v == "number"){
14779 }else if(typeof v == "boolean"){
14780 enc = "b:" + (v ? "1" : "0");
14781 }else if(v instanceof Date){
14782 enc = "d:" + v.toGMTString();
14783 }else if(v instanceof Array){
14785 for(var i = 0, len = v.length; i < len; i++){
14786 flat += this.encodeValue(v[i]);
14787 if(i != len-1) flat += "^";
14790 }else if(typeof v == "object"){
14793 if(typeof v[key] != "function"){
14794 flat += key + "=" + this.encodeValue(v[key]) + "^";
14797 enc = "o:" + flat.substring(0, flat.length-1);
14801 return escape(enc);
14807 * Ext JS Library 1.1.1
14808 * Copyright(c) 2006-2007, Ext JS, LLC.
14810 * Originally Released Under LGPL - original licence link has changed is not relivant.
14813 * <script type="text/javascript">
14816 * @class Roo.state.Manager
14817 * This is the global state manager. By default all components that are "state aware" check this class
14818 * for state information if you don't pass them a custom state provider. In order for this class
14819 * to be useful, it must be initialized with a provider when your application initializes.
14821 // in your initialization function
14823 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14825 // supposed you have a {@link Roo.BorderLayout}
14826 var layout = new Roo.BorderLayout(...);
14827 layout.restoreState();
14828 // or a {Roo.BasicDialog}
14829 var dialog = new Roo.BasicDialog(...);
14830 dialog.restoreState();
14834 Roo.state.Manager = function(){
14835 var provider = new Roo.state.Provider();
14839 * Configures the default state provider for your application
14840 * @param {Provider} stateProvider The state provider to set
14842 setProvider : function(stateProvider){
14843 provider = stateProvider;
14847 * Returns the current value for a key
14848 * @param {String} name The key name
14849 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14850 * @return {Mixed} The state data
14852 get : function(key, defaultValue){
14853 return provider.get(key, defaultValue);
14857 * Sets the value for a key
14858 * @param {String} name The key name
14859 * @param {Mixed} value The state data
14861 set : function(key, value){
14862 provider.set(key, value);
14866 * Clears a value from the state
14867 * @param {String} name The key name
14869 clear : function(key){
14870 provider.clear(key);
14874 * Gets the currently configured state provider
14875 * @return {Provider} The state provider
14877 getProvider : function(){
14884 * Ext JS Library 1.1.1
14885 * Copyright(c) 2006-2007, Ext JS, LLC.
14887 * Originally Released Under LGPL - original licence link has changed is not relivant.
14890 * <script type="text/javascript">
14893 * @class Roo.state.CookieProvider
14894 * @extends Roo.state.Provider
14895 * The default Provider implementation which saves state via cookies.
14898 var cp = new Roo.state.CookieProvider({
14900 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14901 domain: "roojs.com"
14903 Roo.state.Manager.setProvider(cp);
14905 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14906 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14907 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14908 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14909 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14910 * domain the page is running on including the 'www' like 'www.roojs.com')
14911 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14913 * Create a new CookieProvider
14914 * @param {Object} config The configuration object
14916 Roo.state.CookieProvider = function(config){
14917 Roo.state.CookieProvider.superclass.constructor.call(this);
14919 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14920 this.domain = null;
14921 this.secure = false;
14922 Roo.apply(this, config);
14923 this.state = this.readCookies();
14926 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14928 set : function(name, value){
14929 if(typeof value == "undefined" || value === null){
14933 this.setCookie(name, value);
14934 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14938 clear : function(name){
14939 this.clearCookie(name);
14940 Roo.state.CookieProvider.superclass.clear.call(this, name);
14944 readCookies : function(){
14946 var c = document.cookie + ";";
14947 var re = /\s?(.*?)=(.*?);/g;
14949 while((matches = re.exec(c)) != null){
14950 var name = matches[1];
14951 var value = matches[2];
14952 if(name && name.substring(0,3) == "ys-"){
14953 cookies[name.substr(3)] = this.decodeValue(value);
14960 setCookie : function(name, value){
14961 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14962 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14963 ((this.path == null) ? "" : ("; path=" + this.path)) +
14964 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14965 ((this.secure == true) ? "; secure" : "");
14969 clearCookie : function(name){
14970 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14971 ((this.path == null) ? "" : ("; path=" + this.path)) +
14972 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14973 ((this.secure == true) ? "; secure" : "");
14977 * Ext JS Library 1.1.1
14978 * Copyright(c) 2006-2007, Ext JS, LLC.
14980 * Originally Released Under LGPL - original licence link has changed is not relivant.
14983 * <script type="text/javascript">
14988 * @class Roo.ComponentMgr
14989 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14992 Roo.ComponentMgr = function(){
14993 var all = new Roo.util.MixedCollection();
14997 * Registers a component.
14998 * @param {Roo.Component} c The component
15000 register : function(c){
15005 * Unregisters a component.
15006 * @param {Roo.Component} c The component
15008 unregister : function(c){
15013 * Returns a component by id
15014 * @param {String} id The component id
15016 get : function(id){
15017 return all.get(id);
15021 * Registers a function that will be called when a specified component is added to ComponentMgr
15022 * @param {String} id The component id
15023 * @param {Funtction} fn The callback function
15024 * @param {Object} scope The scope of the callback
15026 onAvailable : function(id, fn, scope){
15027 all.on("add", function(index, o){
15029 fn.call(scope || o, o);
15030 all.un("add", fn, scope);
15037 * Ext JS Library 1.1.1
15038 * Copyright(c) 2006-2007, Ext JS, LLC.
15040 * Originally Released Under LGPL - original licence link has changed is not relivant.
15043 * <script type="text/javascript">
15047 * @class Roo.Component
15048 * @extends Roo.util.Observable
15049 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15050 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15051 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15052 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15053 * All visual components (widgets) that require rendering into a layout should subclass Component.
15055 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15056 * 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
15057 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15059 Roo.Component = function(config){
15060 config = config || {};
15061 if(config.tagName || config.dom || typeof config == "string"){ // element object
15062 config = {el: config, id: config.id || config};
15064 this.initialConfig = config;
15066 Roo.apply(this, config);
15070 * Fires after the component is disabled.
15071 * @param {Roo.Component} this
15076 * Fires after the component is enabled.
15077 * @param {Roo.Component} this
15081 * @event beforeshow
15082 * Fires before the component is shown. Return false to stop the show.
15083 * @param {Roo.Component} this
15088 * Fires after the component is shown.
15089 * @param {Roo.Component} this
15093 * @event beforehide
15094 * Fires before the component is hidden. Return false to stop the hide.
15095 * @param {Roo.Component} this
15100 * Fires after the component is hidden.
15101 * @param {Roo.Component} this
15105 * @event beforerender
15106 * Fires before the component is rendered. Return false to stop the render.
15107 * @param {Roo.Component} this
15109 beforerender : true,
15112 * Fires after the component is rendered.
15113 * @param {Roo.Component} this
15117 * @event beforedestroy
15118 * Fires before the component is destroyed. Return false to stop the destroy.
15119 * @param {Roo.Component} this
15121 beforedestroy : true,
15124 * Fires after the component is destroyed.
15125 * @param {Roo.Component} this
15130 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15132 Roo.ComponentMgr.register(this);
15133 Roo.Component.superclass.constructor.call(this);
15134 this.initComponent();
15135 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15136 this.render(this.renderTo);
15137 delete this.renderTo;
15142 Roo.Component.AUTO_ID = 1000;
15144 Roo.extend(Roo.Component, Roo.util.Observable, {
15146 * @scope Roo.Component.prototype
15148 * true if this component is hidden. Read-only.
15153 * true if this component is disabled. Read-only.
15158 * true if this component has been rendered. Read-only.
15162 /** @cfg {String} disableClass
15163 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15165 disabledClass : "x-item-disabled",
15166 /** @cfg {Boolean} allowDomMove
15167 * Whether the component can move the Dom node when rendering (defaults to true).
15169 allowDomMove : true,
15170 /** @cfg {String} hideMode
15171 * How this component should hidden. Supported values are
15172 * "visibility" (css visibility), "offsets" (negative offset position) and
15173 * "display" (css display) - defaults to "display".
15175 hideMode: 'display',
15178 ctype : "Roo.Component",
15181 * @cfg {String} actionMode
15182 * which property holds the element that used for hide() / show() / disable() / enable()
15188 getActionEl : function(){
15189 return this[this.actionMode];
15192 initComponent : Roo.emptyFn,
15194 * If this is a lazy rendering component, render it to its container element.
15195 * @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.
15197 render : function(container, position){
15198 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15199 if(!container && this.el){
15200 this.el = Roo.get(this.el);
15201 container = this.el.dom.parentNode;
15202 this.allowDomMove = false;
15204 this.container = Roo.get(container);
15205 this.rendered = true;
15206 if(position !== undefined){
15207 if(typeof position == 'number'){
15208 position = this.container.dom.childNodes[position];
15210 position = Roo.getDom(position);
15213 this.onRender(this.container, position || null);
15215 this.el.addClass(this.cls);
15219 this.el.applyStyles(this.style);
15222 this.fireEvent("render", this);
15223 this.afterRender(this.container);
15235 // default function is not really useful
15236 onRender : function(ct, position){
15238 this.el = Roo.get(this.el);
15239 if(this.allowDomMove !== false){
15240 ct.dom.insertBefore(this.el.dom, position);
15246 getAutoCreate : function(){
15247 var cfg = typeof this.autoCreate == "object" ?
15248 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15249 if(this.id && !cfg.id){
15256 afterRender : Roo.emptyFn,
15259 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15260 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15262 destroy : function(){
15263 if(this.fireEvent("beforedestroy", this) !== false){
15264 this.purgeListeners();
15265 this.beforeDestroy();
15267 this.el.removeAllListeners();
15269 if(this.actionMode == "container"){
15270 this.container.remove();
15274 Roo.ComponentMgr.unregister(this);
15275 this.fireEvent("destroy", this);
15280 beforeDestroy : function(){
15285 onDestroy : function(){
15290 * Returns the underlying {@link Roo.Element}.
15291 * @return {Roo.Element} The element
15293 getEl : function(){
15298 * Returns the id of this component.
15301 getId : function(){
15306 * Try to focus this component.
15307 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15308 * @return {Roo.Component} this
15310 focus : function(selectText){
15313 if(selectText === true){
15314 this.el.dom.select();
15329 * Disable this component.
15330 * @return {Roo.Component} this
15332 disable : function(){
15336 this.disabled = true;
15337 this.fireEvent("disable", this);
15342 onDisable : function(){
15343 this.getActionEl().addClass(this.disabledClass);
15344 this.el.dom.disabled = true;
15348 * Enable this component.
15349 * @return {Roo.Component} this
15351 enable : function(){
15355 this.disabled = false;
15356 this.fireEvent("enable", this);
15361 onEnable : function(){
15362 this.getActionEl().removeClass(this.disabledClass);
15363 this.el.dom.disabled = false;
15367 * Convenience function for setting disabled/enabled by boolean.
15368 * @param {Boolean} disabled
15370 setDisabled : function(disabled){
15371 this[disabled ? "disable" : "enable"]();
15375 * Show this component.
15376 * @return {Roo.Component} this
15379 if(this.fireEvent("beforeshow", this) !== false){
15380 this.hidden = false;
15384 this.fireEvent("show", this);
15390 onShow : function(){
15391 var ae = this.getActionEl();
15392 if(this.hideMode == 'visibility'){
15393 ae.dom.style.visibility = "visible";
15394 }else if(this.hideMode == 'offsets'){
15395 ae.removeClass('x-hidden');
15397 ae.dom.style.display = "";
15402 * Hide this component.
15403 * @return {Roo.Component} this
15406 if(this.fireEvent("beforehide", this) !== false){
15407 this.hidden = true;
15411 this.fireEvent("hide", this);
15417 onHide : function(){
15418 var ae = this.getActionEl();
15419 if(this.hideMode == 'visibility'){
15420 ae.dom.style.visibility = "hidden";
15421 }else if(this.hideMode == 'offsets'){
15422 ae.addClass('x-hidden');
15424 ae.dom.style.display = "none";
15429 * Convenience function to hide or show this component by boolean.
15430 * @param {Boolean} visible True to show, false to hide
15431 * @return {Roo.Component} this
15433 setVisible: function(visible){
15443 * Returns true if this component is visible.
15445 isVisible : function(){
15446 return this.getActionEl().isVisible();
15449 cloneConfig : function(overrides){
15450 overrides = overrides || {};
15451 var id = overrides.id || Roo.id();
15452 var cfg = Roo.applyIf(overrides, this.initialConfig);
15453 cfg.id = id; // prevent dup id
15454 return new this.constructor(cfg);
15458 * Ext JS Library 1.1.1
15459 * Copyright(c) 2006-2007, Ext JS, LLC.
15461 * Originally Released Under LGPL - original licence link has changed is not relivant.
15464 * <script type="text/javascript">
15468 * @class Roo.BoxComponent
15469 * @extends Roo.Component
15470 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15471 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15472 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15473 * layout containers.
15475 * @param {Roo.Element/String/Object} config The configuration options.
15477 Roo.BoxComponent = function(config){
15478 Roo.Component.call(this, config);
15482 * Fires after the component is resized.
15483 * @param {Roo.Component} this
15484 * @param {Number} adjWidth The box-adjusted width that was set
15485 * @param {Number} adjHeight The box-adjusted height that was set
15486 * @param {Number} rawWidth The width that was originally specified
15487 * @param {Number} rawHeight The height that was originally specified
15492 * Fires after the component is moved.
15493 * @param {Roo.Component} this
15494 * @param {Number} x The new x position
15495 * @param {Number} y The new y position
15501 Roo.extend(Roo.BoxComponent, Roo.Component, {
15502 // private, set in afterRender to signify that the component has been rendered
15504 // private, used to defer height settings to subclasses
15505 deferHeight: false,
15506 /** @cfg {Number} width
15507 * width (optional) size of component
15509 /** @cfg {Number} height
15510 * height (optional) size of component
15514 * Sets the width and height of the component. This method fires the resize event. This method can accept
15515 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15516 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15517 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15518 * @return {Roo.BoxComponent} this
15520 setSize : function(w, h){
15521 // support for standard size objects
15522 if(typeof w == 'object'){
15527 if(!this.boxReady){
15533 // prevent recalcs when not needed
15534 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15537 this.lastSize = {width: w, height: h};
15539 var adj = this.adjustSize(w, h);
15540 var aw = adj.width, ah = adj.height;
15541 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15542 var rz = this.getResizeEl();
15543 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15544 rz.setSize(aw, ah);
15545 }else if(!this.deferHeight && ah !== undefined){
15547 }else if(aw !== undefined){
15550 this.onResize(aw, ah, w, h);
15551 this.fireEvent('resize', this, aw, ah, w, h);
15557 * Gets the current size of the component's underlying element.
15558 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15560 getSize : function(){
15561 return this.el.getSize();
15565 * Gets the current XY position of the component's underlying element.
15566 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15567 * @return {Array} The XY position of the element (e.g., [100, 200])
15569 getPosition : function(local){
15570 if(local === true){
15571 return [this.el.getLeft(true), this.el.getTop(true)];
15573 return this.xy || this.el.getXY();
15577 * Gets the current box measurements of the component's underlying element.
15578 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15579 * @returns {Object} box An object in the format {x, y, width, height}
15581 getBox : function(local){
15582 var s = this.el.getSize();
15584 s.x = this.el.getLeft(true);
15585 s.y = this.el.getTop(true);
15587 var xy = this.xy || this.el.getXY();
15595 * Sets the current box measurements of the component's underlying element.
15596 * @param {Object} box An object in the format {x, y, width, height}
15597 * @returns {Roo.BoxComponent} this
15599 updateBox : function(box){
15600 this.setSize(box.width, box.height);
15601 this.setPagePosition(box.x, box.y);
15606 getResizeEl : function(){
15607 return this.resizeEl || this.el;
15611 getPositionEl : function(){
15612 return this.positionEl || this.el;
15616 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15617 * This method fires the move event.
15618 * @param {Number} left The new left
15619 * @param {Number} top The new top
15620 * @returns {Roo.BoxComponent} this
15622 setPosition : function(x, y){
15625 if(!this.boxReady){
15628 var adj = this.adjustPosition(x, y);
15629 var ax = adj.x, ay = adj.y;
15631 var el = this.getPositionEl();
15632 if(ax !== undefined || ay !== undefined){
15633 if(ax !== undefined && ay !== undefined){
15634 el.setLeftTop(ax, ay);
15635 }else if(ax !== undefined){
15637 }else if(ay !== undefined){
15640 this.onPosition(ax, ay);
15641 this.fireEvent('move', this, ax, ay);
15647 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15648 * This method fires the move event.
15649 * @param {Number} x The new x position
15650 * @param {Number} y The new y position
15651 * @returns {Roo.BoxComponent} this
15653 setPagePosition : function(x, y){
15656 if(!this.boxReady){
15659 if(x === undefined || y === undefined){ // cannot translate undefined points
15662 var p = this.el.translatePoints(x, y);
15663 this.setPosition(p.left, p.top);
15668 onRender : function(ct, position){
15669 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15671 this.resizeEl = Roo.get(this.resizeEl);
15673 if(this.positionEl){
15674 this.positionEl = Roo.get(this.positionEl);
15679 afterRender : function(){
15680 Roo.BoxComponent.superclass.afterRender.call(this);
15681 this.boxReady = true;
15682 this.setSize(this.width, this.height);
15683 if(this.x || this.y){
15684 this.setPosition(this.x, this.y);
15686 if(this.pageX || this.pageY){
15687 this.setPagePosition(this.pageX, this.pageY);
15692 * Force the component's size to recalculate based on the underlying element's current height and width.
15693 * @returns {Roo.BoxComponent} this
15695 syncSize : function(){
15696 delete this.lastSize;
15697 this.setSize(this.el.getWidth(), this.el.getHeight());
15702 * Called after the component is resized, this method is empty by default but can be implemented by any
15703 * subclass that needs to perform custom logic after a resize occurs.
15704 * @param {Number} adjWidth The box-adjusted width that was set
15705 * @param {Number} adjHeight The box-adjusted height that was set
15706 * @param {Number} rawWidth The width that was originally specified
15707 * @param {Number} rawHeight The height that was originally specified
15709 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15714 * Called after the component is moved, this method is empty by default but can be implemented by any
15715 * subclass that needs to perform custom logic after a move occurs.
15716 * @param {Number} x The new x position
15717 * @param {Number} y The new y position
15719 onPosition : function(x, y){
15724 adjustSize : function(w, h){
15725 if(this.autoWidth){
15728 if(this.autoHeight){
15731 return {width : w, height: h};
15735 adjustPosition : function(x, y){
15736 return {x : x, y: y};
15739 * Original code for Roojs - LGPL
15740 * <script type="text/javascript">
15744 * @class Roo.XComponent
15745 * A delayed Element creator...
15746 * Or a way to group chunks of interface together.
15747 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15748 * used in conjunction with XComponent.build() it will create an instance of each element,
15749 * then call addxtype() to build the User interface.
15751 * Mypart.xyx = new Roo.XComponent({
15753 parent : 'Mypart.xyz', // empty == document.element.!!
15757 disabled : function() {}
15759 tree : function() { // return an tree of xtype declared components
15763 xtype : 'NestedLayoutPanel',
15770 * It can be used to build a big heiracy, with parent etc.
15771 * or you can just use this to render a single compoent to a dom element
15772 * MYPART.render(Roo.Element | String(id) | dom_element )
15779 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15780 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15782 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15784 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15785 * - if mulitple topModules exist, the last one is defined as the top module.
15789 * When the top level or multiple modules are to embedded into a existing HTML page,
15790 * the parent element can container '#id' of the element where the module will be drawn.
15794 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15795 * it relies more on a include mechanism, where sub modules are included into an outer page.
15796 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15798 * Bootstrap Roo Included elements
15800 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15801 * hence confusing the component builder as it thinks there are multiple top level elements.
15805 * @extends Roo.util.Observable
15807 * @param cfg {Object} configuration of component
15810 Roo.XComponent = function(cfg) {
15811 Roo.apply(this, cfg);
15815 * Fires when this the componnt is built
15816 * @param {Roo.XComponent} c the component
15821 this.region = this.region || 'center'; // default..
15822 Roo.XComponent.register(this);
15823 this.modules = false;
15824 this.el = false; // where the layout goes..
15828 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15831 * The created element (with Roo.factory())
15832 * @type {Roo.Layout}
15838 * for BC - use el in new code
15839 * @type {Roo.Layout}
15845 * for BC - use el in new code
15846 * @type {Roo.Layout}
15851 * @cfg {Function|boolean} disabled
15852 * If this module is disabled by some rule, return true from the funtion
15857 * @cfg {String} parent
15858 * Name of parent element which it get xtype added to..
15863 * @cfg {String} order
15864 * Used to set the order in which elements are created (usefull for multiple tabs)
15869 * @cfg {String} name
15870 * String to display while loading.
15874 * @cfg {String} region
15875 * Region to render component to (defaults to center)
15880 * @cfg {Array} items
15881 * A single item array - the first element is the root of the tree..
15882 * It's done this way to stay compatible with the Xtype system...
15888 * The method that retuns the tree of parts that make up this compoennt
15895 * render element to dom or tree
15896 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15899 render : function(el)
15903 var hp = this.parent ? 1 : 0;
15906 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15907 // if parent is a '#.....' string, then let's use that..
15908 var ename = this.parent.substr(1);
15909 this.parent = false;
15912 case 'bootstrap-body' :
15913 if (typeof(Roo.bootstrap.Body) != 'undefined') {
15914 this.parent = { el : new Roo.bootstrap.Body() };
15915 Roo.log("setting el to doc body");
15918 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15922 this.parent = { el : true};
15925 el = Roo.get(ename);
15930 if (!el && !this.parent) {
15931 Roo.log("Warning - element can not be found :#" + ename );
15935 Roo.log("EL:");Roo.log(el);
15936 Roo.log("this.parent.el:");Roo.log(this.parent.el);
15938 var tree = this._tree ? this._tree() : this.tree();
15940 // altertive root elements ??? - we need a better way to indicate these.
15941 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15942 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15944 if (!this.parent && is_alt) {
15945 //el = Roo.get(document.body);
15946 this.parent = { el : true };
15951 if (!this.parent) {
15953 Roo.log("no parent - creating one");
15955 el = el ? Roo.get(el) : false;
15957 // it's a top level one..
15959 el : new Roo.BorderLayout(el || document.body, {
15965 tabPosition: 'top',
15966 //resizeTabs: true,
15967 alwaysShowTabs: el && hp? false : true,
15968 hideTabs: el || !hp ? true : false,
15975 if (!this.parent.el) {
15976 // probably an old style ctor, which has been disabled.
15980 // The 'tree' method is '_tree now'
15982 tree.region = tree.region || this.region;
15984 if (this.parent.el === true) {
15985 // bootstrap... - body..
15986 this.parent.el = Roo.factory(tree);
15989 this.el = this.parent.el.addxtype(tree);
15990 this.fireEvent('built', this);
15992 this.panel = this.el;
15993 this.layout = this.panel.layout;
15994 this.parentLayout = this.parent.layout || false;
16000 Roo.apply(Roo.XComponent, {
16002 * @property hideProgress
16003 * true to disable the building progress bar.. usefull on single page renders.
16006 hideProgress : false,
16008 * @property buildCompleted
16009 * True when the builder has completed building the interface.
16012 buildCompleted : false,
16015 * @property topModule
16016 * the upper most module - uses document.element as it's constructor.
16023 * @property modules
16024 * array of modules to be created by registration system.
16025 * @type {Array} of Roo.XComponent
16030 * @property elmodules
16031 * array of modules to be created by which use #ID
16032 * @type {Array} of Roo.XComponent
16038 * @property build_from_html
16039 * Build elements from html - used by bootstrap HTML stuff
16040 * - this is cleared after build is completed
16041 * @type {boolean} true (default false)
16044 build_from_html : false,
16047 * Register components to be built later.
16049 * This solves the following issues
16050 * - Building is not done on page load, but after an authentication process has occured.
16051 * - Interface elements are registered on page load
16052 * - Parent Interface elements may not be loaded before child, so this handles that..
16059 module : 'Pman.Tab.projectMgr',
16061 parent : 'Pman.layout',
16062 disabled : false, // or use a function..
16065 * * @param {Object} details about module
16067 register : function(obj) {
16069 Roo.XComponent.event.fireEvent('register', obj);
16070 switch(typeof(obj.disabled) ) {
16076 if ( obj.disabled() ) {
16082 if (obj.disabled) {
16088 this.modules.push(obj);
16092 * convert a string to an object..
16093 * eg. 'AAA.BBB' -> finds AAA.BBB
16097 toObject : function(str)
16099 if (!str || typeof(str) == 'object') {
16102 if (str.substring(0,1) == '#') {
16106 var ar = str.split('.');
16111 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16113 throw "Module not found : " + str;
16117 throw "Module not found : " + str;
16119 Roo.each(ar, function(e) {
16120 if (typeof(o[e]) == 'undefined') {
16121 throw "Module not found : " + str;
16132 * move modules into their correct place in the tree..
16135 preBuild : function ()
16138 Roo.each(this.modules , function (obj)
16140 Roo.XComponent.event.fireEvent('beforebuild', obj);
16142 var opar = obj.parent;
16144 obj.parent = this.toObject(opar);
16146 Roo.log("parent:toObject failed: " + e.toString());
16151 Roo.debug && Roo.log("GOT top level module");
16152 Roo.debug && Roo.log(obj);
16153 obj.modules = new Roo.util.MixedCollection(false,
16154 function(o) { return o.order + '' }
16156 this.topModule = obj;
16159 // parent is a string (usually a dom element name..)
16160 if (typeof(obj.parent) == 'string') {
16161 this.elmodules.push(obj);
16164 if (obj.parent.constructor != Roo.XComponent) {
16165 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16167 if (!obj.parent.modules) {
16168 obj.parent.modules = new Roo.util.MixedCollection(false,
16169 function(o) { return o.order + '' }
16172 if (obj.parent.disabled) {
16173 obj.disabled = true;
16175 obj.parent.modules.add(obj);
16180 * make a list of modules to build.
16181 * @return {Array} list of modules.
16184 buildOrder : function()
16187 var cmp = function(a,b) {
16188 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16190 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16191 throw "No top level modules to build";
16194 // make a flat list in order of modules to build.
16195 var mods = this.topModule ? [ this.topModule ] : [];
16198 // elmodules (is a list of DOM based modules )
16199 Roo.each(this.elmodules, function(e) {
16201 if (!this.topModule &&
16202 typeof(e.parent) == 'string' &&
16203 e.parent.substring(0,1) == '#' &&
16204 Roo.get(e.parent.substr(1))
16207 _this.topModule = e;
16213 // add modules to their parents..
16214 var addMod = function(m) {
16215 Roo.debug && Roo.log("build Order: add: " + m.name);
16218 if (m.modules && !m.disabled) {
16219 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16220 m.modules.keySort('ASC', cmp );
16221 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16223 m.modules.each(addMod);
16225 Roo.debug && Roo.log("build Order: no child modules");
16227 // not sure if this is used any more..
16229 m.finalize.name = m.name + " (clean up) ";
16230 mods.push(m.finalize);
16234 if (this.topModule && this.topModule.modules) {
16235 this.topModule.modules.keySort('ASC', cmp );
16236 this.topModule.modules.each(addMod);
16242 * Build the registered modules.
16243 * @param {Object} parent element.
16244 * @param {Function} optional method to call after module has been added.
16248 build : function(opts)
16251 if (typeof(opts) != 'undefined') {
16252 Roo.apply(this,opts);
16256 var mods = this.buildOrder();
16258 //this.allmods = mods;
16259 //Roo.debug && Roo.log(mods);
16261 if (!mods.length) { // should not happen
16262 throw "NO modules!!!";
16266 var msg = "Building Interface...";
16267 // flash it up as modal - so we store the mask!?
16268 if (!this.hideProgress && Roo.MessageBox) {
16269 Roo.MessageBox.show({ title: 'loading' });
16270 Roo.MessageBox.show({
16271 title: "Please wait...",
16280 var total = mods.length;
16283 var progressRun = function() {
16284 if (!mods.length) {
16285 Roo.debug && Roo.log('hide?');
16286 if (!this.hideProgress && Roo.MessageBox) {
16287 Roo.MessageBox.hide();
16289 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16291 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16297 var m = mods.shift();
16300 Roo.debug && Roo.log(m);
16301 // not sure if this is supported any more.. - modules that are are just function
16302 if (typeof(m) == 'function') {
16304 return progressRun.defer(10, _this);
16308 msg = "Building Interface " + (total - mods.length) +
16310 (m.name ? (' - ' + m.name) : '');
16311 Roo.debug && Roo.log(msg);
16312 if (!this.hideProgress && Roo.MessageBox) {
16313 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16317 // is the module disabled?
16318 var disabled = (typeof(m.disabled) == 'function') ?
16319 m.disabled.call(m.module.disabled) : m.disabled;
16323 return progressRun(); // we do not update the display!
16331 // it's 10 on top level, and 1 on others??? why...
16332 return progressRun.defer(10, _this);
16335 progressRun.defer(1, _this);
16349 * wrapper for event.on - aliased later..
16350 * Typically use to register a event handler for register:
16352 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16361 Roo.XComponent.event = new Roo.util.Observable({
16365 * Fires when an Component is registered,
16366 * set the disable property on the Component to stop registration.
16367 * @param {Roo.XComponent} c the component being registerd.
16372 * @event beforebuild
16373 * Fires before each Component is built
16374 * can be used to apply permissions.
16375 * @param {Roo.XComponent} c the component being registerd.
16378 'beforebuild' : true,
16380 * @event buildcomplete
16381 * Fires on the top level element when all elements have been built
16382 * @param {Roo.XComponent} the top level component.
16384 'buildcomplete' : true
16389 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16392 * Ext JS Library 1.1.1
16393 * Copyright(c) 2006-2007, Ext JS, LLC.
16395 * Originally Released Under LGPL - original licence link has changed is not relivant.
16398 * <script type="text/javascript">
16404 * These classes are derivatives of the similarly named classes in the YUI Library.
16405 * The original license:
16406 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16407 * Code licensed under the BSD License:
16408 * http://developer.yahoo.net/yui/license.txt
16413 var Event=Roo.EventManager;
16414 var Dom=Roo.lib.Dom;
16417 * @class Roo.dd.DragDrop
16418 * @extends Roo.util.Observable
16419 * Defines the interface and base operation of items that that can be
16420 * dragged or can be drop targets. It was designed to be extended, overriding
16421 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16422 * Up to three html elements can be associated with a DragDrop instance:
16424 * <li>linked element: the element that is passed into the constructor.
16425 * This is the element which defines the boundaries for interaction with
16426 * other DragDrop objects.</li>
16427 * <li>handle element(s): The drag operation only occurs if the element that
16428 * was clicked matches a handle element. By default this is the linked
16429 * element, but there are times that you will want only a portion of the
16430 * linked element to initiate the drag operation, and the setHandleElId()
16431 * method provides a way to define this.</li>
16432 * <li>drag element: this represents the element that would be moved along
16433 * with the cursor during a drag operation. By default, this is the linked
16434 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16435 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16438 * This class should not be instantiated until the onload event to ensure that
16439 * the associated elements are available.
16440 * The following would define a DragDrop obj that would interact with any
16441 * other DragDrop obj in the "group1" group:
16443 * dd = new Roo.dd.DragDrop("div1", "group1");
16445 * Since none of the event handlers have been implemented, nothing would
16446 * actually happen if you were to run the code above. Normally you would
16447 * override this class or one of the default implementations, but you can
16448 * also override the methods you want on an instance of the class...
16450 * dd.onDragDrop = function(e, id) {
16451 * alert("dd was dropped on " + id);
16455 * @param {String} id of the element that is linked to this instance
16456 * @param {String} sGroup the group of related DragDrop objects
16457 * @param {object} config an object containing configurable attributes
16458 * Valid properties for DragDrop:
16459 * padding, isTarget, maintainOffset, primaryButtonOnly
16461 Roo.dd.DragDrop = function(id, sGroup, config) {
16463 this.init(id, sGroup, config);
16468 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16471 * The id of the element associated with this object. This is what we
16472 * refer to as the "linked element" because the size and position of
16473 * this element is used to determine when the drag and drop objects have
16481 * Configuration attributes passed into the constructor
16488 * The id of the element that will be dragged. By default this is same
16489 * as the linked element , but could be changed to another element. Ex:
16491 * @property dragElId
16498 * the id of the element that initiates the drag operation. By default
16499 * this is the linked element, but could be changed to be a child of this
16500 * element. This lets us do things like only starting the drag when the
16501 * header element within the linked html element is clicked.
16502 * @property handleElId
16509 * An associative array of HTML tags that will be ignored if clicked.
16510 * @property invalidHandleTypes
16511 * @type {string: string}
16513 invalidHandleTypes: null,
16516 * An associative array of ids for elements that will be ignored if clicked
16517 * @property invalidHandleIds
16518 * @type {string: string}
16520 invalidHandleIds: null,
16523 * An indexted array of css class names for elements that will be ignored
16525 * @property invalidHandleClasses
16528 invalidHandleClasses: null,
16531 * The linked element's absolute X position at the time the drag was
16533 * @property startPageX
16540 * The linked element's absolute X position at the time the drag was
16542 * @property startPageY
16549 * The group defines a logical collection of DragDrop objects that are
16550 * related. Instances only get events when interacting with other
16551 * DragDrop object in the same group. This lets us define multiple
16552 * groups using a single DragDrop subclass if we want.
16554 * @type {string: string}
16559 * Individual drag/drop instances can be locked. This will prevent
16560 * onmousedown start drag.
16568 * Lock this instance
16571 lock: function() { this.locked = true; },
16574 * Unlock this instace
16577 unlock: function() { this.locked = false; },
16580 * By default, all insances can be a drop target. This can be disabled by
16581 * setting isTarget to false.
16588 * The padding configured for this drag and drop object for calculating
16589 * the drop zone intersection with this object.
16596 * Cached reference to the linked element
16597 * @property _domRef
16603 * Internal typeof flag
16604 * @property __ygDragDrop
16607 __ygDragDrop: true,
16610 * Set to true when horizontal contraints are applied
16611 * @property constrainX
16618 * Set to true when vertical contraints are applied
16619 * @property constrainY
16626 * The left constraint
16634 * The right constraint
16642 * The up constraint
16651 * The down constraint
16659 * Maintain offsets when we resetconstraints. Set to true when you want
16660 * the position of the element relative to its parent to stay the same
16661 * when the page changes
16663 * @property maintainOffset
16666 maintainOffset: false,
16669 * Array of pixel locations the element will snap to if we specified a
16670 * horizontal graduation/interval. This array is generated automatically
16671 * when you define a tick interval.
16678 * Array of pixel locations the element will snap to if we specified a
16679 * vertical graduation/interval. This array is generated automatically
16680 * when you define a tick interval.
16687 * By default the drag and drop instance will only respond to the primary
16688 * button click (left button for a right-handed mouse). Set to true to
16689 * allow drag and drop to start with any mouse click that is propogated
16691 * @property primaryButtonOnly
16694 primaryButtonOnly: true,
16697 * The availabe property is false until the linked dom element is accessible.
16698 * @property available
16704 * By default, drags can only be initiated if the mousedown occurs in the
16705 * region the linked element is. This is done in part to work around a
16706 * bug in some browsers that mis-report the mousedown if the previous
16707 * mouseup happened outside of the window. This property is set to true
16708 * if outer handles are defined.
16710 * @property hasOuterHandles
16714 hasOuterHandles: false,
16717 * Code that executes immediately before the startDrag event
16718 * @method b4StartDrag
16721 b4StartDrag: function(x, y) { },
16724 * Abstract method called after a drag/drop object is clicked
16725 * and the drag or mousedown time thresholds have beeen met.
16726 * @method startDrag
16727 * @param {int} X click location
16728 * @param {int} Y click location
16730 startDrag: function(x, y) { /* override this */ },
16733 * Code that executes immediately before the onDrag event
16737 b4Drag: function(e) { },
16740 * Abstract method called during the onMouseMove event while dragging an
16743 * @param {Event} e the mousemove event
16745 onDrag: function(e) { /* override this */ },
16748 * Abstract method called when this element fist begins hovering over
16749 * another DragDrop obj
16750 * @method onDragEnter
16751 * @param {Event} e the mousemove event
16752 * @param {String|DragDrop[]} id In POINT mode, the element
16753 * id this is hovering over. In INTERSECT mode, an array of one or more
16754 * dragdrop items being hovered over.
16756 onDragEnter: function(e, id) { /* override this */ },
16759 * Code that executes immediately before the onDragOver event
16760 * @method b4DragOver
16763 b4DragOver: function(e) { },
16766 * Abstract method called when this element is hovering over another
16768 * @method onDragOver
16769 * @param {Event} e the mousemove event
16770 * @param {String|DragDrop[]} id In POINT mode, the element
16771 * id this is hovering over. In INTERSECT mode, an array of dd items
16772 * being hovered over.
16774 onDragOver: function(e, id) { /* override this */ },
16777 * Code that executes immediately before the onDragOut event
16778 * @method b4DragOut
16781 b4DragOut: function(e) { },
16784 * Abstract method called when we are no longer hovering over an element
16785 * @method onDragOut
16786 * @param {Event} e the mousemove event
16787 * @param {String|DragDrop[]} id In POINT mode, the element
16788 * id this was hovering over. In INTERSECT mode, an array of dd items
16789 * that the mouse is no longer over.
16791 onDragOut: function(e, id) { /* override this */ },
16794 * Code that executes immediately before the onDragDrop event
16795 * @method b4DragDrop
16798 b4DragDrop: function(e) { },
16801 * Abstract method called when this item is dropped on another DragDrop
16803 * @method onDragDrop
16804 * @param {Event} e the mouseup event
16805 * @param {String|DragDrop[]} id In POINT mode, the element
16806 * id this was dropped on. In INTERSECT mode, an array of dd items this
16809 onDragDrop: function(e, id) { /* override this */ },
16812 * Abstract method called when this item is dropped on an area with no
16814 * @method onInvalidDrop
16815 * @param {Event} e the mouseup event
16817 onInvalidDrop: function(e) { /* override this */ },
16820 * Code that executes immediately before the endDrag event
16821 * @method b4EndDrag
16824 b4EndDrag: function(e) { },
16827 * Fired when we are done dragging the object
16829 * @param {Event} e the mouseup event
16831 endDrag: function(e) { /* override this */ },
16834 * Code executed immediately before the onMouseDown event
16835 * @method b4MouseDown
16836 * @param {Event} e the mousedown event
16839 b4MouseDown: function(e) { },
16842 * Event handler that fires when a drag/drop obj gets a mousedown
16843 * @method onMouseDown
16844 * @param {Event} e the mousedown event
16846 onMouseDown: function(e) { /* override this */ },
16849 * Event handler that fires when a drag/drop obj gets a mouseup
16850 * @method onMouseUp
16851 * @param {Event} e the mouseup event
16853 onMouseUp: function(e) { /* override this */ },
16856 * Override the onAvailable method to do what is needed after the initial
16857 * position was determined.
16858 * @method onAvailable
16860 onAvailable: function () {
16864 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16867 defaultPadding : {left:0, right:0, top:0, bottom:0},
16870 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16874 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16875 { dragElId: "existingProxyDiv" });
16876 dd.startDrag = function(){
16877 this.constrainTo("parent-id");
16880 * Or you can initalize it using the {@link Roo.Element} object:
16882 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16883 startDrag : function(){
16884 this.constrainTo("parent-id");
16888 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16889 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16890 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16891 * an object containing the sides to pad. For example: {right:10, bottom:10}
16892 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16894 constrainTo : function(constrainTo, pad, inContent){
16895 if(typeof pad == "number"){
16896 pad = {left: pad, right:pad, top:pad, bottom:pad};
16898 pad = pad || this.defaultPadding;
16899 var b = Roo.get(this.getEl()).getBox();
16900 var ce = Roo.get(constrainTo);
16901 var s = ce.getScroll();
16902 var c, cd = ce.dom;
16903 if(cd == document.body){
16904 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16907 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16911 var topSpace = b.y - c.y;
16912 var leftSpace = b.x - c.x;
16914 this.resetConstraints();
16915 this.setXConstraint(leftSpace - (pad.left||0), // left
16916 c.width - leftSpace - b.width - (pad.right||0) //right
16918 this.setYConstraint(topSpace - (pad.top||0), //top
16919 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16924 * Returns a reference to the linked element
16926 * @return {HTMLElement} the html element
16928 getEl: function() {
16929 if (!this._domRef) {
16930 this._domRef = Roo.getDom(this.id);
16933 return this._domRef;
16937 * Returns a reference to the actual element to drag. By default this is
16938 * the same as the html element, but it can be assigned to another
16939 * element. An example of this can be found in Roo.dd.DDProxy
16940 * @method getDragEl
16941 * @return {HTMLElement} the html element
16943 getDragEl: function() {
16944 return Roo.getDom(this.dragElId);
16948 * Sets up the DragDrop object. Must be called in the constructor of any
16949 * Roo.dd.DragDrop subclass
16951 * @param id the id of the linked element
16952 * @param {String} sGroup the group of related items
16953 * @param {object} config configuration attributes
16955 init: function(id, sGroup, config) {
16956 this.initTarget(id, sGroup, config);
16957 if (!Roo.isTouch) {
16958 Event.on(this.id, "mousedown", this.handleMouseDown, this);
16960 Event.on(this.id, "touchstart", this.handleMouseDown, this);
16961 // Event.on(this.id, "selectstart", Event.preventDefault);
16965 * Initializes Targeting functionality only... the object does not
16966 * get a mousedown handler.
16967 * @method initTarget
16968 * @param id the id of the linked element
16969 * @param {String} sGroup the group of related items
16970 * @param {object} config configuration attributes
16972 initTarget: function(id, sGroup, config) {
16974 // configuration attributes
16975 this.config = config || {};
16977 // create a local reference to the drag and drop manager
16978 this.DDM = Roo.dd.DDM;
16979 // initialize the groups array
16982 // assume that we have an element reference instead of an id if the
16983 // parameter is not a string
16984 if (typeof id !== "string") {
16991 // add to an interaction group
16992 this.addToGroup((sGroup) ? sGroup : "default");
16994 // We don't want to register this as the handle with the manager
16995 // so we just set the id rather than calling the setter.
16996 this.handleElId = id;
16998 // the linked element is the element that gets dragged by default
16999 this.setDragElId(id);
17001 // by default, clicked anchors will not start drag operations.
17002 this.invalidHandleTypes = { A: "A" };
17003 this.invalidHandleIds = {};
17004 this.invalidHandleClasses = [];
17006 this.applyConfig();
17008 this.handleOnAvailable();
17012 * Applies the configuration parameters that were passed into the constructor.
17013 * This is supposed to happen at each level through the inheritance chain. So
17014 * a DDProxy implentation will execute apply config on DDProxy, DD, and
17015 * DragDrop in order to get all of the parameters that are available in
17017 * @method applyConfig
17019 applyConfig: function() {
17021 // configurable properties:
17022 // padding, isTarget, maintainOffset, primaryButtonOnly
17023 this.padding = this.config.padding || [0, 0, 0, 0];
17024 this.isTarget = (this.config.isTarget !== false);
17025 this.maintainOffset = (this.config.maintainOffset);
17026 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
17031 * Executed when the linked element is available
17032 * @method handleOnAvailable
17035 handleOnAvailable: function() {
17036 this.available = true;
17037 this.resetConstraints();
17038 this.onAvailable();
17042 * Configures the padding for the target zone in px. Effectively expands
17043 * (or reduces) the virtual object size for targeting calculations.
17044 * Supports css-style shorthand; if only one parameter is passed, all sides
17045 * will have that padding, and if only two are passed, the top and bottom
17046 * will have the first param, the left and right the second.
17047 * @method setPadding
17048 * @param {int} iTop Top pad
17049 * @param {int} iRight Right pad
17050 * @param {int} iBot Bot pad
17051 * @param {int} iLeft Left pad
17053 setPadding: function(iTop, iRight, iBot, iLeft) {
17054 // this.padding = [iLeft, iRight, iTop, iBot];
17055 if (!iRight && 0 !== iRight) {
17056 this.padding = [iTop, iTop, iTop, iTop];
17057 } else if (!iBot && 0 !== iBot) {
17058 this.padding = [iTop, iRight, iTop, iRight];
17060 this.padding = [iTop, iRight, iBot, iLeft];
17065 * Stores the initial placement of the linked element.
17066 * @method setInitialPosition
17067 * @param {int} diffX the X offset, default 0
17068 * @param {int} diffY the Y offset, default 0
17070 setInitPosition: function(diffX, diffY) {
17071 var el = this.getEl();
17073 if (!this.DDM.verifyEl(el)) {
17077 var dx = diffX || 0;
17078 var dy = diffY || 0;
17080 var p = Dom.getXY( el );
17082 this.initPageX = p[0] - dx;
17083 this.initPageY = p[1] - dy;
17085 this.lastPageX = p[0];
17086 this.lastPageY = p[1];
17089 this.setStartPosition(p);
17093 * Sets the start position of the element. This is set when the obj
17094 * is initialized, the reset when a drag is started.
17095 * @method setStartPosition
17096 * @param pos current position (from previous lookup)
17099 setStartPosition: function(pos) {
17100 var p = pos || Dom.getXY( this.getEl() );
17101 this.deltaSetXY = null;
17103 this.startPageX = p[0];
17104 this.startPageY = p[1];
17108 * Add this instance to a group of related drag/drop objects. All
17109 * instances belong to at least one group, and can belong to as many
17110 * groups as needed.
17111 * @method addToGroup
17112 * @param sGroup {string} the name of the group
17114 addToGroup: function(sGroup) {
17115 this.groups[sGroup] = true;
17116 this.DDM.regDragDrop(this, sGroup);
17120 * Remove's this instance from the supplied interaction group
17121 * @method removeFromGroup
17122 * @param {string} sGroup The group to drop
17124 removeFromGroup: function(sGroup) {
17125 if (this.groups[sGroup]) {
17126 delete this.groups[sGroup];
17129 this.DDM.removeDDFromGroup(this, sGroup);
17133 * Allows you to specify that an element other than the linked element
17134 * will be moved with the cursor during a drag
17135 * @method setDragElId
17136 * @param id {string} the id of the element that will be used to initiate the drag
17138 setDragElId: function(id) {
17139 this.dragElId = id;
17143 * Allows you to specify a child of the linked element that should be
17144 * used to initiate the drag operation. An example of this would be if
17145 * you have a content div with text and links. Clicking anywhere in the
17146 * content area would normally start the drag operation. Use this method
17147 * to specify that an element inside of the content div is the element
17148 * that starts the drag operation.
17149 * @method setHandleElId
17150 * @param id {string} the id of the element that will be used to
17151 * initiate the drag.
17153 setHandleElId: function(id) {
17154 if (typeof id !== "string") {
17157 this.handleElId = id;
17158 this.DDM.regHandle(this.id, id);
17162 * Allows you to set an element outside of the linked element as a drag
17164 * @method setOuterHandleElId
17165 * @param id the id of the element that will be used to initiate the drag
17167 setOuterHandleElId: function(id) {
17168 if (typeof id !== "string") {
17171 Event.on(id, "mousedown",
17172 this.handleMouseDown, this);
17173 this.setHandleElId(id);
17175 this.hasOuterHandles = true;
17179 * Remove all drag and drop hooks for this element
17182 unreg: function() {
17183 Event.un(this.id, "mousedown",
17184 this.handleMouseDown);
17185 Event.un(this.id, "touchstart",
17186 this.handleMouseDown);
17187 this._domRef = null;
17188 this.DDM._remove(this);
17191 destroy : function(){
17196 * Returns true if this instance is locked, or the drag drop mgr is locked
17197 * (meaning that all drag/drop is disabled on the page.)
17199 * @return {boolean} true if this obj or all drag/drop is locked, else
17202 isLocked: function() {
17203 return (this.DDM.isLocked() || this.locked);
17207 * Fired when this object is clicked
17208 * @method handleMouseDown
17210 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17213 handleMouseDown: function(e, oDD){
17215 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17216 //Roo.log('not touch/ button !=0');
17219 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17220 return; // double touch..
17224 if (this.isLocked()) {
17225 //Roo.log('locked');
17229 this.DDM.refreshCache(this.groups);
17230 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17231 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17232 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17233 //Roo.log('no outer handes or not over target');
17236 // Roo.log('check validator');
17237 if (this.clickValidator(e)) {
17238 // Roo.log('validate success');
17239 // set the initial element position
17240 this.setStartPosition();
17243 this.b4MouseDown(e);
17244 this.onMouseDown(e);
17246 this.DDM.handleMouseDown(e, this);
17248 this.DDM.stopEvent(e);
17256 clickValidator: function(e) {
17257 var target = e.getTarget();
17258 return ( this.isValidHandleChild(target) &&
17259 (this.id == this.handleElId ||
17260 this.DDM.handleWasClicked(target, this.id)) );
17264 * Allows you to specify a tag name that should not start a drag operation
17265 * when clicked. This is designed to facilitate embedding links within a
17266 * drag handle that do something other than start the drag.
17267 * @method addInvalidHandleType
17268 * @param {string} tagName the type of element to exclude
17270 addInvalidHandleType: function(tagName) {
17271 var type = tagName.toUpperCase();
17272 this.invalidHandleTypes[type] = type;
17276 * Lets you to specify an element id for a child of a drag handle
17277 * that should not initiate a drag
17278 * @method addInvalidHandleId
17279 * @param {string} id the element id of the element you wish to ignore
17281 addInvalidHandleId: function(id) {
17282 if (typeof id !== "string") {
17285 this.invalidHandleIds[id] = id;
17289 * Lets you specify a css class of elements that will not initiate a drag
17290 * @method addInvalidHandleClass
17291 * @param {string} cssClass the class of the elements you wish to ignore
17293 addInvalidHandleClass: function(cssClass) {
17294 this.invalidHandleClasses.push(cssClass);
17298 * Unsets an excluded tag name set by addInvalidHandleType
17299 * @method removeInvalidHandleType
17300 * @param {string} tagName the type of element to unexclude
17302 removeInvalidHandleType: function(tagName) {
17303 var type = tagName.toUpperCase();
17304 // this.invalidHandleTypes[type] = null;
17305 delete this.invalidHandleTypes[type];
17309 * Unsets an invalid handle id
17310 * @method removeInvalidHandleId
17311 * @param {string} id the id of the element to re-enable
17313 removeInvalidHandleId: function(id) {
17314 if (typeof id !== "string") {
17317 delete this.invalidHandleIds[id];
17321 * Unsets an invalid css class
17322 * @method removeInvalidHandleClass
17323 * @param {string} cssClass the class of the element(s) you wish to
17326 removeInvalidHandleClass: function(cssClass) {
17327 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17328 if (this.invalidHandleClasses[i] == cssClass) {
17329 delete this.invalidHandleClasses[i];
17335 * Checks the tag exclusion list to see if this click should be ignored
17336 * @method isValidHandleChild
17337 * @param {HTMLElement} node the HTMLElement to evaluate
17338 * @return {boolean} true if this is a valid tag type, false if not
17340 isValidHandleChild: function(node) {
17343 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17346 nodeName = node.nodeName.toUpperCase();
17348 nodeName = node.nodeName;
17350 valid = valid && !this.invalidHandleTypes[nodeName];
17351 valid = valid && !this.invalidHandleIds[node.id];
17353 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17354 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17363 * Create the array of horizontal tick marks if an interval was specified
17364 * in setXConstraint().
17365 * @method setXTicks
17368 setXTicks: function(iStartX, iTickSize) {
17370 this.xTickSize = iTickSize;
17374 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17376 this.xTicks[this.xTicks.length] = i;
17381 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17383 this.xTicks[this.xTicks.length] = i;
17388 this.xTicks.sort(this.DDM.numericSort) ;
17392 * Create the array of vertical tick marks if an interval was specified in
17393 * setYConstraint().
17394 * @method setYTicks
17397 setYTicks: function(iStartY, iTickSize) {
17399 this.yTickSize = iTickSize;
17403 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17405 this.yTicks[this.yTicks.length] = i;
17410 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17412 this.yTicks[this.yTicks.length] = i;
17417 this.yTicks.sort(this.DDM.numericSort) ;
17421 * By default, the element can be dragged any place on the screen. Use
17422 * this method to limit the horizontal travel of the element. Pass in
17423 * 0,0 for the parameters if you want to lock the drag to the y axis.
17424 * @method setXConstraint
17425 * @param {int} iLeft the number of pixels the element can move to the left
17426 * @param {int} iRight the number of pixels the element can move to the
17428 * @param {int} iTickSize optional parameter for specifying that the
17430 * should move iTickSize pixels at a time.
17432 setXConstraint: function(iLeft, iRight, iTickSize) {
17433 this.leftConstraint = iLeft;
17434 this.rightConstraint = iRight;
17436 this.minX = this.initPageX - iLeft;
17437 this.maxX = this.initPageX + iRight;
17438 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17440 this.constrainX = true;
17444 * Clears any constraints applied to this instance. Also clears ticks
17445 * since they can't exist independent of a constraint at this time.
17446 * @method clearConstraints
17448 clearConstraints: function() {
17449 this.constrainX = false;
17450 this.constrainY = false;
17455 * Clears any tick interval defined for this instance
17456 * @method clearTicks
17458 clearTicks: function() {
17459 this.xTicks = null;
17460 this.yTicks = null;
17461 this.xTickSize = 0;
17462 this.yTickSize = 0;
17466 * By default, the element can be dragged any place on the screen. Set
17467 * this to limit the vertical travel of the element. Pass in 0,0 for the
17468 * parameters if you want to lock the drag to the x axis.
17469 * @method setYConstraint
17470 * @param {int} iUp the number of pixels the element can move up
17471 * @param {int} iDown the number of pixels the element can move down
17472 * @param {int} iTickSize optional parameter for specifying that the
17473 * element should move iTickSize pixels at a time.
17475 setYConstraint: function(iUp, iDown, iTickSize) {
17476 this.topConstraint = iUp;
17477 this.bottomConstraint = iDown;
17479 this.minY = this.initPageY - iUp;
17480 this.maxY = this.initPageY + iDown;
17481 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17483 this.constrainY = true;
17488 * resetConstraints must be called if you manually reposition a dd element.
17489 * @method resetConstraints
17490 * @param {boolean} maintainOffset
17492 resetConstraints: function() {
17495 // Maintain offsets if necessary
17496 if (this.initPageX || this.initPageX === 0) {
17497 // figure out how much this thing has moved
17498 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17499 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17501 this.setInitPosition(dx, dy);
17503 // This is the first time we have detected the element's position
17505 this.setInitPosition();
17508 if (this.constrainX) {
17509 this.setXConstraint( this.leftConstraint,
17510 this.rightConstraint,
17514 if (this.constrainY) {
17515 this.setYConstraint( this.topConstraint,
17516 this.bottomConstraint,
17522 * Normally the drag element is moved pixel by pixel, but we can specify
17523 * that it move a number of pixels at a time. This method resolves the
17524 * location when we have it set up like this.
17526 * @param {int} val where we want to place the object
17527 * @param {int[]} tickArray sorted array of valid points
17528 * @return {int} the closest tick
17531 getTick: function(val, tickArray) {
17534 // If tick interval is not defined, it is effectively 1 pixel,
17535 // so we return the value passed to us.
17537 } else if (tickArray[0] >= val) {
17538 // The value is lower than the first tick, so we return the first
17540 return tickArray[0];
17542 for (var i=0, len=tickArray.length; i<len; ++i) {
17544 if (tickArray[next] && tickArray[next] >= val) {
17545 var diff1 = val - tickArray[i];
17546 var diff2 = tickArray[next] - val;
17547 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17551 // The value is larger than the last tick, so we return the last
17553 return tickArray[tickArray.length - 1];
17560 * @return {string} string representation of the dd obj
17562 toString: function() {
17563 return ("DragDrop " + this.id);
17571 * Ext JS Library 1.1.1
17572 * Copyright(c) 2006-2007, Ext JS, LLC.
17574 * Originally Released Under LGPL - original licence link has changed is not relivant.
17577 * <script type="text/javascript">
17582 * The drag and drop utility provides a framework for building drag and drop
17583 * applications. In addition to enabling drag and drop for specific elements,
17584 * the drag and drop elements are tracked by the manager class, and the
17585 * interactions between the various elements are tracked during the drag and
17586 * the implementing code is notified about these important moments.
17589 // Only load the library once. Rewriting the manager class would orphan
17590 // existing drag and drop instances.
17591 if (!Roo.dd.DragDropMgr) {
17594 * @class Roo.dd.DragDropMgr
17595 * DragDropMgr is a singleton that tracks the element interaction for
17596 * all DragDrop items in the window. Generally, you will not call
17597 * this class directly, but it does have helper methods that could
17598 * be useful in your DragDrop implementations.
17601 Roo.dd.DragDropMgr = function() {
17603 var Event = Roo.EventManager;
17608 * Two dimensional Array of registered DragDrop objects. The first
17609 * dimension is the DragDrop item group, the second the DragDrop
17612 * @type {string: string}
17619 * Array of element ids defined as drag handles. Used to determine
17620 * if the element that generated the mousedown event is actually the
17621 * handle and not the html element itself.
17622 * @property handleIds
17623 * @type {string: string}
17630 * the DragDrop object that is currently being dragged
17631 * @property dragCurrent
17639 * the DragDrop object(s) that are being hovered over
17640 * @property dragOvers
17648 * the X distance between the cursor and the object being dragged
17657 * the Y distance between the cursor and the object being dragged
17666 * Flag to determine if we should prevent the default behavior of the
17667 * events we define. By default this is true, but this can be set to
17668 * false if you need the default behavior (not recommended)
17669 * @property preventDefault
17673 preventDefault: true,
17676 * Flag to determine if we should stop the propagation of the events
17677 * we generate. This is true by default but you may want to set it to
17678 * false if the html element contains other features that require the
17680 * @property stopPropagation
17684 stopPropagation: true,
17687 * Internal flag that is set to true when drag and drop has been
17689 * @property initialized
17696 * All drag and drop can be disabled.
17704 * Called the first time an element is registered.
17710 this.initialized = true;
17714 * In point mode, drag and drop interaction is defined by the
17715 * location of the cursor during the drag/drop
17723 * In intersect mode, drag and drop interactio nis defined by the
17724 * overlap of two or more drag and drop objects.
17725 * @property INTERSECT
17732 * The current drag and drop mode. Default: POINT
17740 * Runs method on all drag and drop objects
17741 * @method _execOnAll
17745 _execOnAll: function(sMethod, args) {
17746 for (var i in this.ids) {
17747 for (var j in this.ids[i]) {
17748 var oDD = this.ids[i][j];
17749 if (! this.isTypeOfDD(oDD)) {
17752 oDD[sMethod].apply(oDD, args);
17758 * Drag and drop initialization. Sets up the global event handlers
17763 _onLoad: function() {
17767 if (!Roo.isTouch) {
17768 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17769 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17771 Event.on(document, "touchend", this.handleMouseUp, this, true);
17772 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17774 Event.on(window, "unload", this._onUnload, this, true);
17775 Event.on(window, "resize", this._onResize, this, true);
17776 // Event.on(window, "mouseout", this._test);
17781 * Reset constraints on all drag and drop objs
17782 * @method _onResize
17786 _onResize: function(e) {
17787 this._execOnAll("resetConstraints", []);
17791 * Lock all drag and drop functionality
17795 lock: function() { this.locked = true; },
17798 * Unlock all drag and drop functionality
17802 unlock: function() { this.locked = false; },
17805 * Is drag and drop locked?
17807 * @return {boolean} True if drag and drop is locked, false otherwise.
17810 isLocked: function() { return this.locked; },
17813 * Location cache that is set for all drag drop objects when a drag is
17814 * initiated, cleared when the drag is finished.
17815 * @property locationCache
17822 * Set useCache to false if you want to force object the lookup of each
17823 * drag and drop linked element constantly during a drag.
17824 * @property useCache
17831 * The number of pixels that the mouse needs to move after the
17832 * mousedown before the drag is initiated. Default=3;
17833 * @property clickPixelThresh
17837 clickPixelThresh: 3,
17840 * The number of milliseconds after the mousedown event to initiate the
17841 * drag if we don't get a mouseup event. Default=1000
17842 * @property clickTimeThresh
17846 clickTimeThresh: 350,
17849 * Flag that indicates that either the drag pixel threshold or the
17850 * mousdown time threshold has been met
17851 * @property dragThreshMet
17856 dragThreshMet: false,
17859 * Timeout used for the click time threshold
17860 * @property clickTimeout
17865 clickTimeout: null,
17868 * The X position of the mousedown event stored for later use when a
17869 * drag threshold is met.
17878 * The Y position of the mousedown event stored for later use when a
17879 * drag threshold is met.
17888 * Each DragDrop instance must be registered with the DragDropMgr.
17889 * This is executed in DragDrop.init()
17890 * @method regDragDrop
17891 * @param {DragDrop} oDD the DragDrop object to register
17892 * @param {String} sGroup the name of the group this element belongs to
17895 regDragDrop: function(oDD, sGroup) {
17896 if (!this.initialized) { this.init(); }
17898 if (!this.ids[sGroup]) {
17899 this.ids[sGroup] = {};
17901 this.ids[sGroup][oDD.id] = oDD;
17905 * Removes the supplied dd instance from the supplied group. Executed
17906 * by DragDrop.removeFromGroup, so don't call this function directly.
17907 * @method removeDDFromGroup
17911 removeDDFromGroup: function(oDD, sGroup) {
17912 if (!this.ids[sGroup]) {
17913 this.ids[sGroup] = {};
17916 var obj = this.ids[sGroup];
17917 if (obj && obj[oDD.id]) {
17918 delete obj[oDD.id];
17923 * Unregisters a drag and drop item. This is executed in
17924 * DragDrop.unreg, use that method instead of calling this directly.
17929 _remove: function(oDD) {
17930 for (var g in oDD.groups) {
17931 if (g && this.ids[g][oDD.id]) {
17932 delete this.ids[g][oDD.id];
17935 delete this.handleIds[oDD.id];
17939 * Each DragDrop handle element must be registered. This is done
17940 * automatically when executing DragDrop.setHandleElId()
17941 * @method regHandle
17942 * @param {String} sDDId the DragDrop id this element is a handle for
17943 * @param {String} sHandleId the id of the element that is the drag
17947 regHandle: function(sDDId, sHandleId) {
17948 if (!this.handleIds[sDDId]) {
17949 this.handleIds[sDDId] = {};
17951 this.handleIds[sDDId][sHandleId] = sHandleId;
17955 * Utility function to determine if a given element has been
17956 * registered as a drag drop item.
17957 * @method isDragDrop
17958 * @param {String} id the element id to check
17959 * @return {boolean} true if this element is a DragDrop item,
17963 isDragDrop: function(id) {
17964 return ( this.getDDById(id) ) ? true : false;
17968 * Returns the drag and drop instances that are in all groups the
17969 * passed in instance belongs to.
17970 * @method getRelated
17971 * @param {DragDrop} p_oDD the obj to get related data for
17972 * @param {boolean} bTargetsOnly if true, only return targetable objs
17973 * @return {DragDrop[]} the related instances
17976 getRelated: function(p_oDD, bTargetsOnly) {
17978 for (var i in p_oDD.groups) {
17979 for (j in this.ids[i]) {
17980 var dd = this.ids[i][j];
17981 if (! this.isTypeOfDD(dd)) {
17984 if (!bTargetsOnly || dd.isTarget) {
17985 oDDs[oDDs.length] = dd;
17994 * Returns true if the specified dd target is a legal target for
17995 * the specifice drag obj
17996 * @method isLegalTarget
17997 * @param {DragDrop} the drag obj
17998 * @param {DragDrop} the target
17999 * @return {boolean} true if the target is a legal target for the
18003 isLegalTarget: function (oDD, oTargetDD) {
18004 var targets = this.getRelated(oDD, true);
18005 for (var i=0, len=targets.length;i<len;++i) {
18006 if (targets[i].id == oTargetDD.id) {
18015 * My goal is to be able to transparently determine if an object is
18016 * typeof DragDrop, and the exact subclass of DragDrop. typeof
18017 * returns "object", oDD.constructor.toString() always returns
18018 * "DragDrop" and not the name of the subclass. So for now it just
18019 * evaluates a well-known variable in DragDrop.
18020 * @method isTypeOfDD
18021 * @param {Object} the object to evaluate
18022 * @return {boolean} true if typeof oDD = DragDrop
18025 isTypeOfDD: function (oDD) {
18026 return (oDD && oDD.__ygDragDrop);
18030 * Utility function to determine if a given element has been
18031 * registered as a drag drop handle for the given Drag Drop object.
18033 * @param {String} id the element id to check
18034 * @return {boolean} true if this element is a DragDrop handle, false
18038 isHandle: function(sDDId, sHandleId) {
18039 return ( this.handleIds[sDDId] &&
18040 this.handleIds[sDDId][sHandleId] );
18044 * Returns the DragDrop instance for a given id
18045 * @method getDDById
18046 * @param {String} id the id of the DragDrop object
18047 * @return {DragDrop} the drag drop object, null if it is not found
18050 getDDById: function(id) {
18051 for (var i in this.ids) {
18052 if (this.ids[i][id]) {
18053 return this.ids[i][id];
18060 * Fired after a registered DragDrop object gets the mousedown event.
18061 * Sets up the events required to track the object being dragged
18062 * @method handleMouseDown
18063 * @param {Event} e the event
18064 * @param oDD the DragDrop object being dragged
18068 handleMouseDown: function(e, oDD) {
18070 Roo.QuickTips.disable();
18072 this.currentTarget = e.getTarget();
18074 this.dragCurrent = oDD;
18076 var el = oDD.getEl();
18078 // track start position
18079 this.startX = e.getPageX();
18080 this.startY = e.getPageY();
18082 this.deltaX = this.startX - el.offsetLeft;
18083 this.deltaY = this.startY - el.offsetTop;
18085 this.dragThreshMet = false;
18087 this.clickTimeout = setTimeout(
18089 var DDM = Roo.dd.DDM;
18090 DDM.startDrag(DDM.startX, DDM.startY);
18092 this.clickTimeThresh );
18096 * Fired when either the drag pixel threshol or the mousedown hold
18097 * time threshold has been met.
18098 * @method startDrag
18099 * @param x {int} the X position of the original mousedown
18100 * @param y {int} the Y position of the original mousedown
18103 startDrag: function(x, y) {
18104 clearTimeout(this.clickTimeout);
18105 if (this.dragCurrent) {
18106 this.dragCurrent.b4StartDrag(x, y);
18107 this.dragCurrent.startDrag(x, y);
18109 this.dragThreshMet = true;
18113 * Internal function to handle the mouseup event. Will be invoked
18114 * from the context of the document.
18115 * @method handleMouseUp
18116 * @param {Event} e the event
18120 handleMouseUp: function(e) {
18123 Roo.QuickTips.enable();
18125 if (! this.dragCurrent) {
18129 clearTimeout(this.clickTimeout);
18131 if (this.dragThreshMet) {
18132 this.fireEvents(e, true);
18142 * Utility to stop event propagation and event default, if these
18143 * features are turned on.
18144 * @method stopEvent
18145 * @param {Event} e the event as returned by this.getEvent()
18148 stopEvent: function(e){
18149 if(this.stopPropagation) {
18150 e.stopPropagation();
18153 if (this.preventDefault) {
18154 e.preventDefault();
18159 * Internal function to clean up event handlers after the drag
18160 * operation is complete
18162 * @param {Event} e the event
18166 stopDrag: function(e) {
18167 // Fire the drag end event for the item that was dragged
18168 if (this.dragCurrent) {
18169 if (this.dragThreshMet) {
18170 this.dragCurrent.b4EndDrag(e);
18171 this.dragCurrent.endDrag(e);
18174 this.dragCurrent.onMouseUp(e);
18177 this.dragCurrent = null;
18178 this.dragOvers = {};
18182 * Internal function to handle the mousemove event. Will be invoked
18183 * from the context of the html element.
18185 * @TODO figure out what we can do about mouse events lost when the
18186 * user drags objects beyond the window boundary. Currently we can
18187 * detect this in internet explorer by verifying that the mouse is
18188 * down during the mousemove event. Firefox doesn't give us the
18189 * button state on the mousemove event.
18190 * @method handleMouseMove
18191 * @param {Event} e the event
18195 handleMouseMove: function(e) {
18196 if (! this.dragCurrent) {
18200 // var button = e.which || e.button;
18202 // check for IE mouseup outside of page boundary
18203 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18205 return this.handleMouseUp(e);
18208 if (!this.dragThreshMet) {
18209 var diffX = Math.abs(this.startX - e.getPageX());
18210 var diffY = Math.abs(this.startY - e.getPageY());
18211 if (diffX > this.clickPixelThresh ||
18212 diffY > this.clickPixelThresh) {
18213 this.startDrag(this.startX, this.startY);
18217 if (this.dragThreshMet) {
18218 this.dragCurrent.b4Drag(e);
18219 this.dragCurrent.onDrag(e);
18220 if(!this.dragCurrent.moveOnly){
18221 this.fireEvents(e, false);
18231 * Iterates over all of the DragDrop elements to find ones we are
18232 * hovering over or dropping on
18233 * @method fireEvents
18234 * @param {Event} e the event
18235 * @param {boolean} isDrop is this a drop op or a mouseover op?
18239 fireEvents: function(e, isDrop) {
18240 var dc = this.dragCurrent;
18242 // If the user did the mouse up outside of the window, we could
18243 // get here even though we have ended the drag.
18244 if (!dc || dc.isLocked()) {
18248 var pt = e.getPoint();
18250 // cache the previous dragOver array
18256 var enterEvts = [];
18258 // Check to see if the object(s) we were hovering over is no longer
18259 // being hovered over so we can fire the onDragOut event
18260 for (var i in this.dragOvers) {
18262 var ddo = this.dragOvers[i];
18264 if (! this.isTypeOfDD(ddo)) {
18268 if (! this.isOverTarget(pt, ddo, this.mode)) {
18269 outEvts.push( ddo );
18272 oldOvers[i] = true;
18273 delete this.dragOvers[i];
18276 for (var sGroup in dc.groups) {
18278 if ("string" != typeof sGroup) {
18282 for (i in this.ids[sGroup]) {
18283 var oDD = this.ids[sGroup][i];
18284 if (! this.isTypeOfDD(oDD)) {
18288 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18289 if (this.isOverTarget(pt, oDD, this.mode)) {
18290 // look for drop interactions
18292 dropEvts.push( oDD );
18293 // look for drag enter and drag over interactions
18296 // initial drag over: dragEnter fires
18297 if (!oldOvers[oDD.id]) {
18298 enterEvts.push( oDD );
18299 // subsequent drag overs: dragOver fires
18301 overEvts.push( oDD );
18304 this.dragOvers[oDD.id] = oDD;
18312 if (outEvts.length) {
18313 dc.b4DragOut(e, outEvts);
18314 dc.onDragOut(e, outEvts);
18317 if (enterEvts.length) {
18318 dc.onDragEnter(e, enterEvts);
18321 if (overEvts.length) {
18322 dc.b4DragOver(e, overEvts);
18323 dc.onDragOver(e, overEvts);
18326 if (dropEvts.length) {
18327 dc.b4DragDrop(e, dropEvts);
18328 dc.onDragDrop(e, dropEvts);
18332 // fire dragout events
18334 for (i=0, len=outEvts.length; i<len; ++i) {
18335 dc.b4DragOut(e, outEvts[i].id);
18336 dc.onDragOut(e, outEvts[i].id);
18339 // fire enter events
18340 for (i=0,len=enterEvts.length; i<len; ++i) {
18341 // dc.b4DragEnter(e, oDD.id);
18342 dc.onDragEnter(e, enterEvts[i].id);
18345 // fire over events
18346 for (i=0,len=overEvts.length; i<len; ++i) {
18347 dc.b4DragOver(e, overEvts[i].id);
18348 dc.onDragOver(e, overEvts[i].id);
18351 // fire drop events
18352 for (i=0, len=dropEvts.length; i<len; ++i) {
18353 dc.b4DragDrop(e, dropEvts[i].id);
18354 dc.onDragDrop(e, dropEvts[i].id);
18359 // notify about a drop that did not find a target
18360 if (isDrop && !dropEvts.length) {
18361 dc.onInvalidDrop(e);
18367 * Helper function for getting the best match from the list of drag
18368 * and drop objects returned by the drag and drop events when we are
18369 * in INTERSECT mode. It returns either the first object that the
18370 * cursor is over, or the object that has the greatest overlap with
18371 * the dragged element.
18372 * @method getBestMatch
18373 * @param {DragDrop[]} dds The array of drag and drop objects
18375 * @return {DragDrop} The best single match
18378 getBestMatch: function(dds) {
18380 // Return null if the input is not what we expect
18381 //if (!dds || !dds.length || dds.length == 0) {
18383 // If there is only one item, it wins
18384 //} else if (dds.length == 1) {
18386 var len = dds.length;
18391 // Loop through the targeted items
18392 for (var i=0; i<len; ++i) {
18394 // If the cursor is over the object, it wins. If the
18395 // cursor is over multiple matches, the first one we come
18397 if (dd.cursorIsOver) {
18400 // Otherwise the object with the most overlap wins
18403 winner.overlap.getArea() < dd.overlap.getArea()) {
18414 * Refreshes the cache of the top-left and bottom-right points of the
18415 * drag and drop objects in the specified group(s). This is in the
18416 * format that is stored in the drag and drop instance, so typical
18419 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18423 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18425 * @TODO this really should be an indexed array. Alternatively this
18426 * method could accept both.
18427 * @method refreshCache
18428 * @param {Object} groups an associative array of groups to refresh
18431 refreshCache: function(groups) {
18432 for (var sGroup in groups) {
18433 if ("string" != typeof sGroup) {
18436 for (var i in this.ids[sGroup]) {
18437 var oDD = this.ids[sGroup][i];
18439 if (this.isTypeOfDD(oDD)) {
18440 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18441 var loc = this.getLocation(oDD);
18443 this.locationCache[oDD.id] = loc;
18445 delete this.locationCache[oDD.id];
18446 // this will unregister the drag and drop object if
18447 // the element is not in a usable state
18456 * This checks to make sure an element exists and is in the DOM. The
18457 * main purpose is to handle cases where innerHTML is used to remove
18458 * drag and drop objects from the DOM. IE provides an 'unspecified
18459 * error' when trying to access the offsetParent of such an element
18461 * @param {HTMLElement} el the element to check
18462 * @return {boolean} true if the element looks usable
18465 verifyEl: function(el) {
18470 parent = el.offsetParent;
18473 parent = el.offsetParent;
18484 * Returns a Region object containing the drag and drop element's position
18485 * and size, including the padding configured for it
18486 * @method getLocation
18487 * @param {DragDrop} oDD the drag and drop object to get the
18489 * @return {Roo.lib.Region} a Region object representing the total area
18490 * the element occupies, including any padding
18491 * the instance is configured for.
18494 getLocation: function(oDD) {
18495 if (! this.isTypeOfDD(oDD)) {
18499 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18502 pos= Roo.lib.Dom.getXY(el);
18510 x2 = x1 + el.offsetWidth;
18512 y2 = y1 + el.offsetHeight;
18514 t = y1 - oDD.padding[0];
18515 r = x2 + oDD.padding[1];
18516 b = y2 + oDD.padding[2];
18517 l = x1 - oDD.padding[3];
18519 return new Roo.lib.Region( t, r, b, l );
18523 * Checks the cursor location to see if it over the target
18524 * @method isOverTarget
18525 * @param {Roo.lib.Point} pt The point to evaluate
18526 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18527 * @return {boolean} true if the mouse is over the target
18531 isOverTarget: function(pt, oTarget, intersect) {
18532 // use cache if available
18533 var loc = this.locationCache[oTarget.id];
18534 if (!loc || !this.useCache) {
18535 loc = this.getLocation(oTarget);
18536 this.locationCache[oTarget.id] = loc;
18544 oTarget.cursorIsOver = loc.contains( pt );
18546 // DragDrop is using this as a sanity check for the initial mousedown
18547 // in this case we are done. In POINT mode, if the drag obj has no
18548 // contraints, we are also done. Otherwise we need to evaluate the
18549 // location of the target as related to the actual location of the
18550 // dragged element.
18551 var dc = this.dragCurrent;
18552 if (!dc || !dc.getTargetCoord ||
18553 (!intersect && !dc.constrainX && !dc.constrainY)) {
18554 return oTarget.cursorIsOver;
18557 oTarget.overlap = null;
18559 // Get the current location of the drag element, this is the
18560 // location of the mouse event less the delta that represents
18561 // where the original mousedown happened on the element. We
18562 // need to consider constraints and ticks as well.
18563 var pos = dc.getTargetCoord(pt.x, pt.y);
18565 var el = dc.getDragEl();
18566 var curRegion = new Roo.lib.Region( pos.y,
18567 pos.x + el.offsetWidth,
18568 pos.y + el.offsetHeight,
18571 var overlap = curRegion.intersect(loc);
18574 oTarget.overlap = overlap;
18575 return (intersect) ? true : oTarget.cursorIsOver;
18582 * unload event handler
18583 * @method _onUnload
18587 _onUnload: function(e, me) {
18588 Roo.dd.DragDropMgr.unregAll();
18592 * Cleans up the drag and drop events and objects.
18597 unregAll: function() {
18599 if (this.dragCurrent) {
18601 this.dragCurrent = null;
18604 this._execOnAll("unreg", []);
18606 for (i in this.elementCache) {
18607 delete this.elementCache[i];
18610 this.elementCache = {};
18615 * A cache of DOM elements
18616 * @property elementCache
18623 * Get the wrapper for the DOM element specified
18624 * @method getElWrapper
18625 * @param {String} id the id of the element to get
18626 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18628 * @deprecated This wrapper isn't that useful
18631 getElWrapper: function(id) {
18632 var oWrapper = this.elementCache[id];
18633 if (!oWrapper || !oWrapper.el) {
18634 oWrapper = this.elementCache[id] =
18635 new this.ElementWrapper(Roo.getDom(id));
18641 * Returns the actual DOM element
18642 * @method getElement
18643 * @param {String} id the id of the elment to get
18644 * @return {Object} The element
18645 * @deprecated use Roo.getDom instead
18648 getElement: function(id) {
18649 return Roo.getDom(id);
18653 * Returns the style property for the DOM element (i.e.,
18654 * document.getElById(id).style)
18656 * @param {String} id the id of the elment to get
18657 * @return {Object} The style property of the element
18658 * @deprecated use Roo.getDom instead
18661 getCss: function(id) {
18662 var el = Roo.getDom(id);
18663 return (el) ? el.style : null;
18667 * Inner class for cached elements
18668 * @class DragDropMgr.ElementWrapper
18673 ElementWrapper: function(el) {
18678 this.el = el || null;
18683 this.id = this.el && el.id;
18685 * A reference to the style property
18688 this.css = this.el && el.style;
18692 * Returns the X position of an html element
18694 * @param el the element for which to get the position
18695 * @return {int} the X coordinate
18697 * @deprecated use Roo.lib.Dom.getX instead
18700 getPosX: function(el) {
18701 return Roo.lib.Dom.getX(el);
18705 * Returns the Y position of an html element
18707 * @param el the element for which to get the position
18708 * @return {int} the Y coordinate
18709 * @deprecated use Roo.lib.Dom.getY instead
18712 getPosY: function(el) {
18713 return Roo.lib.Dom.getY(el);
18717 * Swap two nodes. In IE, we use the native method, for others we
18718 * emulate the IE behavior
18720 * @param n1 the first node to swap
18721 * @param n2 the other node to swap
18724 swapNode: function(n1, n2) {
18728 var p = n2.parentNode;
18729 var s = n2.nextSibling;
18732 p.insertBefore(n1, n2);
18733 } else if (n2 == n1.nextSibling) {
18734 p.insertBefore(n2, n1);
18736 n1.parentNode.replaceChild(n2, n1);
18737 p.insertBefore(n1, s);
18743 * Returns the current scroll position
18744 * @method getScroll
18748 getScroll: function () {
18749 var t, l, dde=document.documentElement, db=document.body;
18750 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18752 l = dde.scrollLeft;
18759 return { top: t, left: l };
18763 * Returns the specified element style property
18765 * @param {HTMLElement} el the element
18766 * @param {string} styleProp the style property
18767 * @return {string} The value of the style property
18768 * @deprecated use Roo.lib.Dom.getStyle
18771 getStyle: function(el, styleProp) {
18772 return Roo.fly(el).getStyle(styleProp);
18776 * Gets the scrollTop
18777 * @method getScrollTop
18778 * @return {int} the document's scrollTop
18781 getScrollTop: function () { return this.getScroll().top; },
18784 * Gets the scrollLeft
18785 * @method getScrollLeft
18786 * @return {int} the document's scrollTop
18789 getScrollLeft: function () { return this.getScroll().left; },
18792 * Sets the x/y position of an element to the location of the
18795 * @param {HTMLElement} moveEl The element to move
18796 * @param {HTMLElement} targetEl The position reference element
18799 moveToEl: function (moveEl, targetEl) {
18800 var aCoord = Roo.lib.Dom.getXY(targetEl);
18801 Roo.lib.Dom.setXY(moveEl, aCoord);
18805 * Numeric array sort function
18806 * @method numericSort
18809 numericSort: function(a, b) { return (a - b); },
18813 * @property _timeoutCount
18820 * Trying to make the load order less important. Without this we get
18821 * an error if this file is loaded before the Event Utility.
18822 * @method _addListeners
18826 _addListeners: function() {
18827 var DDM = Roo.dd.DDM;
18828 if ( Roo.lib.Event && document ) {
18831 if (DDM._timeoutCount > 2000) {
18833 setTimeout(DDM._addListeners, 10);
18834 if (document && document.body) {
18835 DDM._timeoutCount += 1;
18842 * Recursively searches the immediate parent and all child nodes for
18843 * the handle element in order to determine wheter or not it was
18845 * @method handleWasClicked
18846 * @param node the html element to inspect
18849 handleWasClicked: function(node, id) {
18850 if (this.isHandle(id, node.id)) {
18853 // check to see if this is a text node child of the one we want
18854 var p = node.parentNode;
18857 if (this.isHandle(id, p.id)) {
18872 // shorter alias, save a few bytes
18873 Roo.dd.DDM = Roo.dd.DragDropMgr;
18874 Roo.dd.DDM._addListeners();
18878 * Ext JS Library 1.1.1
18879 * Copyright(c) 2006-2007, Ext JS, LLC.
18881 * Originally Released Under LGPL - original licence link has changed is not relivant.
18884 * <script type="text/javascript">
18889 * A DragDrop implementation where the linked element follows the
18890 * mouse cursor during a drag.
18891 * @extends Roo.dd.DragDrop
18893 * @param {String} id the id of the linked element
18894 * @param {String} sGroup the group of related DragDrop items
18895 * @param {object} config an object containing configurable attributes
18896 * Valid properties for DD:
18899 Roo.dd.DD = function(id, sGroup, config) {
18901 this.init(id, sGroup, config);
18905 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18908 * When set to true, the utility automatically tries to scroll the browser
18909 * window wehn a drag and drop element is dragged near the viewport boundary.
18910 * Defaults to true.
18917 * Sets the pointer offset to the distance between the linked element's top
18918 * left corner and the location the element was clicked
18919 * @method autoOffset
18920 * @param {int} iPageX the X coordinate of the click
18921 * @param {int} iPageY the Y coordinate of the click
18923 autoOffset: function(iPageX, iPageY) {
18924 var x = iPageX - this.startPageX;
18925 var y = iPageY - this.startPageY;
18926 this.setDelta(x, y);
18930 * Sets the pointer offset. You can call this directly to force the
18931 * offset to be in a particular location (e.g., pass in 0,0 to set it
18932 * to the center of the object)
18934 * @param {int} iDeltaX the distance from the left
18935 * @param {int} iDeltaY the distance from the top
18937 setDelta: function(iDeltaX, iDeltaY) {
18938 this.deltaX = iDeltaX;
18939 this.deltaY = iDeltaY;
18943 * Sets the drag element to the location of the mousedown or click event,
18944 * maintaining the cursor location relative to the location on the element
18945 * that was clicked. Override this if you want to place the element in a
18946 * location other than where the cursor is.
18947 * @method setDragElPos
18948 * @param {int} iPageX the X coordinate of the mousedown or drag event
18949 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18951 setDragElPos: function(iPageX, iPageY) {
18952 // the first time we do this, we are going to check to make sure
18953 // the element has css positioning
18955 var el = this.getDragEl();
18956 this.alignElWithMouse(el, iPageX, iPageY);
18960 * Sets the element to the location of the mousedown or click event,
18961 * maintaining the cursor location relative to the location on the element
18962 * that was clicked. Override this if you want to place the element in a
18963 * location other than where the cursor is.
18964 * @method alignElWithMouse
18965 * @param {HTMLElement} el the element to move
18966 * @param {int} iPageX the X coordinate of the mousedown or drag event
18967 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18969 alignElWithMouse: function(el, iPageX, iPageY) {
18970 var oCoord = this.getTargetCoord(iPageX, iPageY);
18971 var fly = el.dom ? el : Roo.fly(el);
18972 if (!this.deltaSetXY) {
18973 var aCoord = [oCoord.x, oCoord.y];
18975 var newLeft = fly.getLeft(true);
18976 var newTop = fly.getTop(true);
18977 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
18979 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
18982 this.cachePosition(oCoord.x, oCoord.y);
18983 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
18988 * Saves the most recent position so that we can reset the constraints and
18989 * tick marks on-demand. We need to know this so that we can calculate the
18990 * number of pixels the element is offset from its original position.
18991 * @method cachePosition
18992 * @param iPageX the current x position (optional, this just makes it so we
18993 * don't have to look it up again)
18994 * @param iPageY the current y position (optional, this just makes it so we
18995 * don't have to look it up again)
18997 cachePosition: function(iPageX, iPageY) {
18999 this.lastPageX = iPageX;
19000 this.lastPageY = iPageY;
19002 var aCoord = Roo.lib.Dom.getXY(this.getEl());
19003 this.lastPageX = aCoord[0];
19004 this.lastPageY = aCoord[1];
19009 * Auto-scroll the window if the dragged object has been moved beyond the
19010 * visible window boundary.
19011 * @method autoScroll
19012 * @param {int} x the drag element's x position
19013 * @param {int} y the drag element's y position
19014 * @param {int} h the height of the drag element
19015 * @param {int} w the width of the drag element
19018 autoScroll: function(x, y, h, w) {
19021 // The client height
19022 var clientH = Roo.lib.Dom.getViewWidth();
19024 // The client width
19025 var clientW = Roo.lib.Dom.getViewHeight();
19027 // The amt scrolled down
19028 var st = this.DDM.getScrollTop();
19030 // The amt scrolled right
19031 var sl = this.DDM.getScrollLeft();
19033 // Location of the bottom of the element
19036 // Location of the right of the element
19039 // The distance from the cursor to the bottom of the visible area,
19040 // adjusted so that we don't scroll if the cursor is beyond the
19041 // element drag constraints
19042 var toBot = (clientH + st - y - this.deltaY);
19044 // The distance from the cursor to the right of the visible area
19045 var toRight = (clientW + sl - x - this.deltaX);
19048 // How close to the edge the cursor must be before we scroll
19049 // var thresh = (document.all) ? 100 : 40;
19052 // How many pixels to scroll per autoscroll op. This helps to reduce
19053 // clunky scrolling. IE is more sensitive about this ... it needs this
19054 // value to be higher.
19055 var scrAmt = (document.all) ? 80 : 30;
19057 // Scroll down if we are near the bottom of the visible page and the
19058 // obj extends below the crease
19059 if ( bot > clientH && toBot < thresh ) {
19060 window.scrollTo(sl, st + scrAmt);
19063 // Scroll up if the window is scrolled down and the top of the object
19064 // goes above the top border
19065 if ( y < st && st > 0 && y - st < thresh ) {
19066 window.scrollTo(sl, st - scrAmt);
19069 // Scroll right if the obj is beyond the right border and the cursor is
19070 // near the border.
19071 if ( right > clientW && toRight < thresh ) {
19072 window.scrollTo(sl + scrAmt, st);
19075 // Scroll left if the window has been scrolled to the right and the obj
19076 // extends past the left border
19077 if ( x < sl && sl > 0 && x - sl < thresh ) {
19078 window.scrollTo(sl - scrAmt, st);
19084 * Finds the location the element should be placed if we want to move
19085 * it to where the mouse location less the click offset would place us.
19086 * @method getTargetCoord
19087 * @param {int} iPageX the X coordinate of the click
19088 * @param {int} iPageY the Y coordinate of the click
19089 * @return an object that contains the coordinates (Object.x and Object.y)
19092 getTargetCoord: function(iPageX, iPageY) {
19095 var x = iPageX - this.deltaX;
19096 var y = iPageY - this.deltaY;
19098 if (this.constrainX) {
19099 if (x < this.minX) { x = this.minX; }
19100 if (x > this.maxX) { x = this.maxX; }
19103 if (this.constrainY) {
19104 if (y < this.minY) { y = this.minY; }
19105 if (y > this.maxY) { y = this.maxY; }
19108 x = this.getTick(x, this.xTicks);
19109 y = this.getTick(y, this.yTicks);
19116 * Sets up config options specific to this class. Overrides
19117 * Roo.dd.DragDrop, but all versions of this method through the
19118 * inheritance chain are called
19120 applyConfig: function() {
19121 Roo.dd.DD.superclass.applyConfig.call(this);
19122 this.scroll = (this.config.scroll !== false);
19126 * Event that fires prior to the onMouseDown event. Overrides
19129 b4MouseDown: function(e) {
19130 // this.resetConstraints();
19131 this.autoOffset(e.getPageX(),
19136 * Event that fires prior to the onDrag event. Overrides
19139 b4Drag: function(e) {
19140 this.setDragElPos(e.getPageX(),
19144 toString: function() {
19145 return ("DD " + this.id);
19148 //////////////////////////////////////////////////////////////////////////
19149 // Debugging ygDragDrop events that can be overridden
19150 //////////////////////////////////////////////////////////////////////////
19152 startDrag: function(x, y) {
19155 onDrag: function(e) {
19158 onDragEnter: function(e, id) {
19161 onDragOver: function(e, id) {
19164 onDragOut: function(e, id) {
19167 onDragDrop: function(e, id) {
19170 endDrag: function(e) {
19177 * Ext JS Library 1.1.1
19178 * Copyright(c) 2006-2007, Ext JS, LLC.
19180 * Originally Released Under LGPL - original licence link has changed is not relivant.
19183 * <script type="text/javascript">
19187 * @class Roo.dd.DDProxy
19188 * A DragDrop implementation that inserts an empty, bordered div into
19189 * the document that follows the cursor during drag operations. At the time of
19190 * the click, the frame div is resized to the dimensions of the linked html
19191 * element, and moved to the exact location of the linked element.
19193 * References to the "frame" element refer to the single proxy element that
19194 * was created to be dragged in place of all DDProxy elements on the
19197 * @extends Roo.dd.DD
19199 * @param {String} id the id of the linked html element
19200 * @param {String} sGroup the group of related DragDrop objects
19201 * @param {object} config an object containing configurable attributes
19202 * Valid properties for DDProxy in addition to those in DragDrop:
19203 * resizeFrame, centerFrame, dragElId
19205 Roo.dd.DDProxy = function(id, sGroup, config) {
19207 this.init(id, sGroup, config);
19213 * The default drag frame div id
19214 * @property Roo.dd.DDProxy.dragElId
19218 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19220 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19223 * By default we resize the drag frame to be the same size as the element
19224 * we want to drag (this is to get the frame effect). We can turn it off
19225 * if we want a different behavior.
19226 * @property resizeFrame
19232 * By default the frame is positioned exactly where the drag element is, so
19233 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19234 * you do not have constraints on the obj is to have the drag frame centered
19235 * around the cursor. Set centerFrame to true for this effect.
19236 * @property centerFrame
19239 centerFrame: false,
19242 * Creates the proxy element if it does not yet exist
19243 * @method createFrame
19245 createFrame: function() {
19247 var body = document.body;
19249 if (!body || !body.firstChild) {
19250 setTimeout( function() { self.createFrame(); }, 50 );
19254 var div = this.getDragEl();
19257 div = document.createElement("div");
19258 div.id = this.dragElId;
19261 s.position = "absolute";
19262 s.visibility = "hidden";
19264 s.border = "2px solid #aaa";
19267 // appendChild can blow up IE if invoked prior to the window load event
19268 // while rendering a table. It is possible there are other scenarios
19269 // that would cause this to happen as well.
19270 body.insertBefore(div, body.firstChild);
19275 * Initialization for the drag frame element. Must be called in the
19276 * constructor of all subclasses
19277 * @method initFrame
19279 initFrame: function() {
19280 this.createFrame();
19283 applyConfig: function() {
19284 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19286 this.resizeFrame = (this.config.resizeFrame !== false);
19287 this.centerFrame = (this.config.centerFrame);
19288 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19292 * Resizes the drag frame to the dimensions of the clicked object, positions
19293 * it over the object, and finally displays it
19294 * @method showFrame
19295 * @param {int} iPageX X click position
19296 * @param {int} iPageY Y click position
19299 showFrame: function(iPageX, iPageY) {
19300 var el = this.getEl();
19301 var dragEl = this.getDragEl();
19302 var s = dragEl.style;
19304 this._resizeProxy();
19306 if (this.centerFrame) {
19307 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19308 Math.round(parseInt(s.height, 10)/2) );
19311 this.setDragElPos(iPageX, iPageY);
19313 Roo.fly(dragEl).show();
19317 * The proxy is automatically resized to the dimensions of the linked
19318 * element when a drag is initiated, unless resizeFrame is set to false
19319 * @method _resizeProxy
19322 _resizeProxy: function() {
19323 if (this.resizeFrame) {
19324 var el = this.getEl();
19325 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19329 // overrides Roo.dd.DragDrop
19330 b4MouseDown: function(e) {
19331 var x = e.getPageX();
19332 var y = e.getPageY();
19333 this.autoOffset(x, y);
19334 this.setDragElPos(x, y);
19337 // overrides Roo.dd.DragDrop
19338 b4StartDrag: function(x, y) {
19339 // show the drag frame
19340 this.showFrame(x, y);
19343 // overrides Roo.dd.DragDrop
19344 b4EndDrag: function(e) {
19345 Roo.fly(this.getDragEl()).hide();
19348 // overrides Roo.dd.DragDrop
19349 // By default we try to move the element to the last location of the frame.
19350 // This is so that the default behavior mirrors that of Roo.dd.DD.
19351 endDrag: function(e) {
19353 var lel = this.getEl();
19354 var del = this.getDragEl();
19356 // Show the drag frame briefly so we can get its position
19357 del.style.visibility = "";
19360 // Hide the linked element before the move to get around a Safari
19362 lel.style.visibility = "hidden";
19363 Roo.dd.DDM.moveToEl(lel, del);
19364 del.style.visibility = "hidden";
19365 lel.style.visibility = "";
19370 beforeMove : function(){
19374 afterDrag : function(){
19378 toString: function() {
19379 return ("DDProxy " + this.id);
19385 * Ext JS Library 1.1.1
19386 * Copyright(c) 2006-2007, Ext JS, LLC.
19388 * Originally Released Under LGPL - original licence link has changed is not relivant.
19391 * <script type="text/javascript">
19395 * @class Roo.dd.DDTarget
19396 * A DragDrop implementation that does not move, but can be a drop
19397 * target. You would get the same result by simply omitting implementation
19398 * for the event callbacks, but this way we reduce the processing cost of the
19399 * event listener and the callbacks.
19400 * @extends Roo.dd.DragDrop
19402 * @param {String} id the id of the element that is a drop target
19403 * @param {String} sGroup the group of related DragDrop objects
19404 * @param {object} config an object containing configurable attributes
19405 * Valid properties for DDTarget in addition to those in
19409 Roo.dd.DDTarget = function(id, sGroup, config) {
19411 this.initTarget(id, sGroup, config);
19413 if (config.listeners || config.events) {
19414 Roo.dd.DragDrop.superclass.constructor.call(this, {
19415 listeners : config.listeners || {},
19416 events : config.events || {}
19421 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19422 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19423 toString: function() {
19424 return ("DDTarget " + this.id);
19429 * Ext JS Library 1.1.1
19430 * Copyright(c) 2006-2007, Ext JS, LLC.
19432 * Originally Released Under LGPL - original licence link has changed is not relivant.
19435 * <script type="text/javascript">
19440 * @class Roo.dd.ScrollManager
19441 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19442 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19445 Roo.dd.ScrollManager = function(){
19446 var ddm = Roo.dd.DragDropMgr;
19453 var onStop = function(e){
19458 var triggerRefresh = function(){
19459 if(ddm.dragCurrent){
19460 ddm.refreshCache(ddm.dragCurrent.groups);
19464 var doScroll = function(){
19465 if(ddm.dragCurrent){
19466 var dds = Roo.dd.ScrollManager;
19468 if(proc.el.scroll(proc.dir, dds.increment)){
19472 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19477 var clearProc = function(){
19479 clearInterval(proc.id);
19486 var startProc = function(el, dir){
19487 Roo.log('scroll startproc');
19491 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19494 var onFire = function(e, isDrop){
19496 if(isDrop || !ddm.dragCurrent){ return; }
19497 var dds = Roo.dd.ScrollManager;
19498 if(!dragEl || dragEl != ddm.dragCurrent){
19499 dragEl = ddm.dragCurrent;
19500 // refresh regions on drag start
19501 dds.refreshCache();
19504 var xy = Roo.lib.Event.getXY(e);
19505 var pt = new Roo.lib.Point(xy[0], xy[1]);
19506 for(var id in els){
19507 var el = els[id], r = el._region;
19508 if(r && r.contains(pt) && el.isScrollable()){
19509 if(r.bottom - pt.y <= dds.thresh){
19511 startProc(el, "down");
19514 }else if(r.right - pt.x <= dds.thresh){
19516 startProc(el, "left");
19519 }else if(pt.y - r.top <= dds.thresh){
19521 startProc(el, "up");
19524 }else if(pt.x - r.left <= dds.thresh){
19526 startProc(el, "right");
19535 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19536 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19540 * Registers new overflow element(s) to auto scroll
19541 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19543 register : function(el){
19544 if(el instanceof Array){
19545 for(var i = 0, len = el.length; i < len; i++) {
19546 this.register(el[i]);
19552 Roo.dd.ScrollManager.els = els;
19556 * Unregisters overflow element(s) so they are no longer scrolled
19557 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19559 unregister : function(el){
19560 if(el instanceof Array){
19561 for(var i = 0, len = el.length; i < len; i++) {
19562 this.unregister(el[i]);
19571 * The number of pixels from the edge of a container the pointer needs to be to
19572 * trigger scrolling (defaults to 25)
19578 * The number of pixels to scroll in each scroll increment (defaults to 50)
19584 * The frequency of scrolls in milliseconds (defaults to 500)
19590 * True to animate the scroll (defaults to true)
19596 * The animation duration in seconds -
19597 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19603 * Manually trigger a cache refresh.
19605 refreshCache : function(){
19606 for(var id in els){
19607 if(typeof els[id] == 'object'){ // for people extending the object prototype
19608 els[id]._region = els[id].getRegion();
19615 * Ext JS Library 1.1.1
19616 * Copyright(c) 2006-2007, Ext JS, LLC.
19618 * Originally Released Under LGPL - original licence link has changed is not relivant.
19621 * <script type="text/javascript">
19626 * @class Roo.dd.Registry
19627 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19628 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19631 Roo.dd.Registry = function(){
19634 var autoIdSeed = 0;
19636 var getId = function(el, autogen){
19637 if(typeof el == "string"){
19641 if(!id && autogen !== false){
19642 id = "roodd-" + (++autoIdSeed);
19650 * Register a drag drop element
19651 * @param {String|HTMLElement} element The id or DOM node to register
19652 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19653 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19654 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19655 * populated in the data object (if applicable):
19657 Value Description<br />
19658 --------- ------------------------------------------<br />
19659 handles Array of DOM nodes that trigger dragging<br />
19660 for the element being registered<br />
19661 isHandle True if the element passed in triggers<br />
19662 dragging itself, else false
19665 register : function(el, data){
19667 if(typeof el == "string"){
19668 el = document.getElementById(el);
19671 elements[getId(el)] = data;
19672 if(data.isHandle !== false){
19673 handles[data.ddel.id] = data;
19676 var hs = data.handles;
19677 for(var i = 0, len = hs.length; i < len; i++){
19678 handles[getId(hs[i])] = data;
19684 * Unregister a drag drop element
19685 * @param {String|HTMLElement} element The id or DOM node to unregister
19687 unregister : function(el){
19688 var id = getId(el, false);
19689 var data = elements[id];
19691 delete elements[id];
19693 var hs = data.handles;
19694 for(var i = 0, len = hs.length; i < len; i++){
19695 delete handles[getId(hs[i], false)];
19702 * Returns the handle registered for a DOM Node by id
19703 * @param {String|HTMLElement} id The DOM node or id to look up
19704 * @return {Object} handle The custom handle data
19706 getHandle : function(id){
19707 if(typeof id != "string"){ // must be element?
19710 return handles[id];
19714 * Returns the handle that is registered for the DOM node that is the target of the event
19715 * @param {Event} e The event
19716 * @return {Object} handle The custom handle data
19718 getHandleFromEvent : function(e){
19719 var t = Roo.lib.Event.getTarget(e);
19720 return t ? handles[t.id] : null;
19724 * Returns a custom data object that is registered for a DOM node by id
19725 * @param {String|HTMLElement} id The DOM node or id to look up
19726 * @return {Object} data The custom data
19728 getTarget : function(id){
19729 if(typeof id != "string"){ // must be element?
19732 return elements[id];
19736 * Returns a custom data object that is registered for the DOM node that is the target of the event
19737 * @param {Event} e The event
19738 * @return {Object} data The custom data
19740 getTargetFromEvent : function(e){
19741 var t = Roo.lib.Event.getTarget(e);
19742 return t ? elements[t.id] || handles[t.id] : null;
19747 * Ext JS Library 1.1.1
19748 * Copyright(c) 2006-2007, Ext JS, LLC.
19750 * Originally Released Under LGPL - original licence link has changed is not relivant.
19753 * <script type="text/javascript">
19758 * @class Roo.dd.StatusProxy
19759 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19760 * default drag proxy used by all Roo.dd components.
19762 * @param {Object} config
19764 Roo.dd.StatusProxy = function(config){
19765 Roo.apply(this, config);
19766 this.id = this.id || Roo.id();
19767 this.el = new Roo.Layer({
19769 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19770 {tag: "div", cls: "x-dd-drop-icon"},
19771 {tag: "div", cls: "x-dd-drag-ghost"}
19774 shadow: !config || config.shadow !== false
19776 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19777 this.dropStatus = this.dropNotAllowed;
19780 Roo.dd.StatusProxy.prototype = {
19782 * @cfg {String} dropAllowed
19783 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19785 dropAllowed : "x-dd-drop-ok",
19787 * @cfg {String} dropNotAllowed
19788 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19790 dropNotAllowed : "x-dd-drop-nodrop",
19793 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19794 * over the current target element.
19795 * @param {String} cssClass The css class for the new drop status indicator image
19797 setStatus : function(cssClass){
19798 cssClass = cssClass || this.dropNotAllowed;
19799 if(this.dropStatus != cssClass){
19800 this.el.replaceClass(this.dropStatus, cssClass);
19801 this.dropStatus = cssClass;
19806 * Resets the status indicator to the default dropNotAllowed value
19807 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19809 reset : function(clearGhost){
19810 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19811 this.dropStatus = this.dropNotAllowed;
19813 this.ghost.update("");
19818 * Updates the contents of the ghost element
19819 * @param {String} html The html that will replace the current innerHTML of the ghost element
19821 update : function(html){
19822 if(typeof html == "string"){
19823 this.ghost.update(html);
19825 this.ghost.update("");
19826 html.style.margin = "0";
19827 this.ghost.dom.appendChild(html);
19829 // ensure float = none set?? cant remember why though.
19830 var el = this.ghost.dom.firstChild;
19832 Roo.fly(el).setStyle('float', 'none');
19837 * Returns the underlying proxy {@link Roo.Layer}
19838 * @return {Roo.Layer} el
19840 getEl : function(){
19845 * Returns the ghost element
19846 * @return {Roo.Element} el
19848 getGhost : function(){
19854 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19856 hide : function(clear){
19864 * Stops the repair animation if it's currently running
19867 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19873 * Displays this proxy
19880 * Force the Layer to sync its shadow and shim positions to the element
19887 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19888 * invalid drop operation by the item being dragged.
19889 * @param {Array} xy The XY position of the element ([x, y])
19890 * @param {Function} callback The function to call after the repair is complete
19891 * @param {Object} scope The scope in which to execute the callback
19893 repair : function(xy, callback, scope){
19894 this.callback = callback;
19895 this.scope = scope;
19896 if(xy && this.animRepair !== false){
19897 this.el.addClass("x-dd-drag-repair");
19898 this.el.hideUnders(true);
19899 this.anim = this.el.shift({
19900 duration: this.repairDuration || .5,
19904 callback: this.afterRepair,
19908 this.afterRepair();
19913 afterRepair : function(){
19915 if(typeof this.callback == "function"){
19916 this.callback.call(this.scope || this);
19918 this.callback = null;
19923 * Ext JS Library 1.1.1
19924 * Copyright(c) 2006-2007, Ext JS, LLC.
19926 * Originally Released Under LGPL - original licence link has changed is not relivant.
19929 * <script type="text/javascript">
19933 * @class Roo.dd.DragSource
19934 * @extends Roo.dd.DDProxy
19935 * A simple class that provides the basic implementation needed to make any element draggable.
19937 * @param {String/HTMLElement/Element} el The container element
19938 * @param {Object} config
19940 Roo.dd.DragSource = function(el, config){
19941 this.el = Roo.get(el);
19942 this.dragData = {};
19944 Roo.apply(this, config);
19947 this.proxy = new Roo.dd.StatusProxy();
19950 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
19951 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
19953 this.dragging = false;
19956 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
19958 * @cfg {String} dropAllowed
19959 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
19961 dropAllowed : "x-dd-drop-ok",
19963 * @cfg {String} dropNotAllowed
19964 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
19966 dropNotAllowed : "x-dd-drop-nodrop",
19969 * Returns the data object associated with this drag source
19970 * @return {Object} data An object containing arbitrary data
19972 getDragData : function(e){
19973 return this.dragData;
19977 onDragEnter : function(e, id){
19978 var target = Roo.dd.DragDropMgr.getDDById(id);
19979 this.cachedTarget = target;
19980 if(this.beforeDragEnter(target, e, id) !== false){
19981 if(target.isNotifyTarget){
19982 var status = target.notifyEnter(this, e, this.dragData);
19983 this.proxy.setStatus(status);
19985 this.proxy.setStatus(this.dropAllowed);
19988 if(this.afterDragEnter){
19990 * An empty function by default, but provided so that you can perform a custom action
19991 * when the dragged item enters the drop target by providing an implementation.
19992 * @param {Roo.dd.DragDrop} target The drop target
19993 * @param {Event} e The event object
19994 * @param {String} id The id of the dragged element
19995 * @method afterDragEnter
19997 this.afterDragEnter(target, e, id);
20003 * An empty function by default, but provided so that you can perform a custom action
20004 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
20005 * @param {Roo.dd.DragDrop} target The drop target
20006 * @param {Event} e The event object
20007 * @param {String} id The id of the dragged element
20008 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20010 beforeDragEnter : function(target, e, id){
20015 alignElWithMouse: function() {
20016 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
20021 onDragOver : function(e, id){
20022 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20023 if(this.beforeDragOver(target, e, id) !== false){
20024 if(target.isNotifyTarget){
20025 var status = target.notifyOver(this, e, this.dragData);
20026 this.proxy.setStatus(status);
20029 if(this.afterDragOver){
20031 * An empty function by default, but provided so that you can perform a custom action
20032 * while the dragged item is over the drop target by providing an implementation.
20033 * @param {Roo.dd.DragDrop} target The drop target
20034 * @param {Event} e The event object
20035 * @param {String} id The id of the dragged element
20036 * @method afterDragOver
20038 this.afterDragOver(target, e, id);
20044 * An empty function by default, but provided so that you can perform a custom action
20045 * while the dragged item is over the drop target and optionally cancel the onDragOver.
20046 * @param {Roo.dd.DragDrop} target The drop target
20047 * @param {Event} e The event object
20048 * @param {String} id The id of the dragged element
20049 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20051 beforeDragOver : function(target, e, id){
20056 onDragOut : function(e, id){
20057 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20058 if(this.beforeDragOut(target, e, id) !== false){
20059 if(target.isNotifyTarget){
20060 target.notifyOut(this, e, this.dragData);
20062 this.proxy.reset();
20063 if(this.afterDragOut){
20065 * An empty function by default, but provided so that you can perform a custom action
20066 * after the dragged item is dragged out of the target without dropping.
20067 * @param {Roo.dd.DragDrop} target The drop target
20068 * @param {Event} e The event object
20069 * @param {String} id The id of the dragged element
20070 * @method afterDragOut
20072 this.afterDragOut(target, e, id);
20075 this.cachedTarget = null;
20079 * An empty function by default, but provided so that you can perform a custom action before the dragged
20080 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20081 * @param {Roo.dd.DragDrop} target The drop target
20082 * @param {Event} e The event object
20083 * @param {String} id The id of the dragged element
20084 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20086 beforeDragOut : function(target, e, id){
20091 onDragDrop : function(e, id){
20092 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20093 if(this.beforeDragDrop(target, e, id) !== false){
20094 if(target.isNotifyTarget){
20095 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20096 this.onValidDrop(target, e, id);
20098 this.onInvalidDrop(target, e, id);
20101 this.onValidDrop(target, e, id);
20104 if(this.afterDragDrop){
20106 * An empty function by default, but provided so that you can perform a custom action
20107 * after a valid drag drop has occurred by providing an implementation.
20108 * @param {Roo.dd.DragDrop} target The drop target
20109 * @param {Event} e The event object
20110 * @param {String} id The id of the dropped element
20111 * @method afterDragDrop
20113 this.afterDragDrop(target, e, id);
20116 delete this.cachedTarget;
20120 * An empty function by default, but provided so that you can perform a custom action before the dragged
20121 * item is dropped onto the target and optionally cancel the onDragDrop.
20122 * @param {Roo.dd.DragDrop} target The drop target
20123 * @param {Event} e The event object
20124 * @param {String} id The id of the dragged element
20125 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20127 beforeDragDrop : function(target, e, id){
20132 onValidDrop : function(target, e, id){
20134 if(this.afterValidDrop){
20136 * An empty function by default, but provided so that you can perform a custom action
20137 * after a valid drop has occurred by providing an implementation.
20138 * @param {Object} target The target DD
20139 * @param {Event} e The event object
20140 * @param {String} id The id of the dropped element
20141 * @method afterInvalidDrop
20143 this.afterValidDrop(target, e, id);
20148 getRepairXY : function(e, data){
20149 return this.el.getXY();
20153 onInvalidDrop : function(target, e, id){
20154 this.beforeInvalidDrop(target, e, id);
20155 if(this.cachedTarget){
20156 if(this.cachedTarget.isNotifyTarget){
20157 this.cachedTarget.notifyOut(this, e, this.dragData);
20159 this.cacheTarget = null;
20161 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20163 if(this.afterInvalidDrop){
20165 * An empty function by default, but provided so that you can perform a custom action
20166 * after an invalid drop has occurred by providing an implementation.
20167 * @param {Event} e The event object
20168 * @param {String} id The id of the dropped element
20169 * @method afterInvalidDrop
20171 this.afterInvalidDrop(e, id);
20176 afterRepair : function(){
20178 this.el.highlight(this.hlColor || "c3daf9");
20180 this.dragging = false;
20184 * An empty function by default, but provided so that you can perform a custom action after an invalid
20185 * drop has occurred.
20186 * @param {Roo.dd.DragDrop} target The drop target
20187 * @param {Event} e The event object
20188 * @param {String} id The id of the dragged element
20189 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20191 beforeInvalidDrop : function(target, e, id){
20196 handleMouseDown : function(e){
20197 if(this.dragging) {
20200 var data = this.getDragData(e);
20201 if(data && this.onBeforeDrag(data, e) !== false){
20202 this.dragData = data;
20204 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20209 * An empty function by default, but provided so that you can perform a custom action before the initial
20210 * drag event begins and optionally cancel it.
20211 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20212 * @param {Event} e The event object
20213 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20215 onBeforeDrag : function(data, e){
20220 * An empty function by default, but provided so that you can perform a custom action once the initial
20221 * drag event has begun. The drag cannot be canceled from this function.
20222 * @param {Number} x The x position of the click on the dragged object
20223 * @param {Number} y The y position of the click on the dragged object
20225 onStartDrag : Roo.emptyFn,
20227 // private - YUI override
20228 startDrag : function(x, y){
20229 this.proxy.reset();
20230 this.dragging = true;
20231 this.proxy.update("");
20232 this.onInitDrag(x, y);
20237 onInitDrag : function(x, y){
20238 var clone = this.el.dom.cloneNode(true);
20239 clone.id = Roo.id(); // prevent duplicate ids
20240 this.proxy.update(clone);
20241 this.onStartDrag(x, y);
20246 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20247 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20249 getProxy : function(){
20254 * Hides the drag source's {@link Roo.dd.StatusProxy}
20256 hideProxy : function(){
20258 this.proxy.reset(true);
20259 this.dragging = false;
20263 triggerCacheRefresh : function(){
20264 Roo.dd.DDM.refreshCache(this.groups);
20267 // private - override to prevent hiding
20268 b4EndDrag: function(e) {
20271 // private - override to prevent moving
20272 endDrag : function(e){
20273 this.onEndDrag(this.dragData, e);
20277 onEndDrag : function(data, e){
20280 // private - pin to cursor
20281 autoOffset : function(x, y) {
20282 this.setDelta(-12, -20);
20286 * Ext JS Library 1.1.1
20287 * Copyright(c) 2006-2007, Ext JS, LLC.
20289 * Originally Released Under LGPL - original licence link has changed is not relivant.
20292 * <script type="text/javascript">
20297 * @class Roo.dd.DropTarget
20298 * @extends Roo.dd.DDTarget
20299 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20300 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20302 * @param {String/HTMLElement/Element} el The container element
20303 * @param {Object} config
20305 Roo.dd.DropTarget = function(el, config){
20306 this.el = Roo.get(el);
20308 var listeners = false; ;
20309 if (config && config.listeners) {
20310 listeners= config.listeners;
20311 delete config.listeners;
20313 Roo.apply(this, config);
20315 if(this.containerScroll){
20316 Roo.dd.ScrollManager.register(this.el);
20320 * @scope Roo.dd.DropTarget
20325 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20326 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20327 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20329 * IMPORTANT : it should set this.overClass and this.dropAllowed
20331 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20332 * @param {Event} e The event
20333 * @param {Object} data An object containing arbitrary data supplied by the drag source
20339 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20340 * This method will be called on every mouse movement while the drag source is over the drop target.
20341 * This default implementation simply returns the dropAllowed config value.
20343 * IMPORTANT : it should set this.dropAllowed
20345 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20346 * @param {Event} e The event
20347 * @param {Object} data An object containing arbitrary data supplied by the drag source
20353 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20354 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20355 * overClass (if any) from the drop element.
20357 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20358 * @param {Event} e The event
20359 * @param {Object} data An object containing arbitrary data supplied by the drag source
20365 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20366 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20367 * implementation that does something to process the drop event and returns true so that the drag source's
20368 * repair action does not run.
20370 * IMPORTANT : it should set this.success
20372 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20373 * @param {Event} e The event
20374 * @param {Object} data An object containing arbitrary data supplied by the drag source
20380 Roo.dd.DropTarget.superclass.constructor.call( this,
20382 this.ddGroup || this.group,
20385 listeners : listeners || {}
20393 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20395 * @cfg {String} overClass
20396 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20399 * @cfg {String} ddGroup
20400 * The drag drop group to handle drop events for
20404 * @cfg {String} dropAllowed
20405 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20407 dropAllowed : "x-dd-drop-ok",
20409 * @cfg {String} dropNotAllowed
20410 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20412 dropNotAllowed : "x-dd-drop-nodrop",
20414 * @cfg {boolean} success
20415 * set this after drop listener..
20419 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20420 * if the drop point is valid for over/enter..
20427 isNotifyTarget : true,
20432 notifyEnter : function(dd, e, data)
20435 this.fireEvent('enter', dd, e, data);
20436 if(this.overClass){
20437 this.el.addClass(this.overClass);
20439 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20440 this.valid ? this.dropAllowed : this.dropNotAllowed
20447 notifyOver : function(dd, e, data)
20450 this.fireEvent('over', dd, e, data);
20451 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20452 this.valid ? this.dropAllowed : this.dropNotAllowed
20459 notifyOut : function(dd, e, data)
20461 this.fireEvent('out', dd, e, data);
20462 if(this.overClass){
20463 this.el.removeClass(this.overClass);
20470 notifyDrop : function(dd, e, data)
20472 this.success = false;
20473 this.fireEvent('drop', dd, e, data);
20474 return this.success;
20478 * Ext JS Library 1.1.1
20479 * Copyright(c) 2006-2007, Ext JS, LLC.
20481 * Originally Released Under LGPL - original licence link has changed is not relivant.
20484 * <script type="text/javascript">
20489 * @class Roo.dd.DragZone
20490 * @extends Roo.dd.DragSource
20491 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20492 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20494 * @param {String/HTMLElement/Element} el The container element
20495 * @param {Object} config
20497 Roo.dd.DragZone = function(el, config){
20498 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20499 if(this.containerScroll){
20500 Roo.dd.ScrollManager.register(this.el);
20504 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20506 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20507 * for auto scrolling during drag operations.
20510 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20511 * method after a failed drop (defaults to "c3daf9" - light blue)
20515 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20516 * for a valid target to drag based on the mouse down. Override this method
20517 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20518 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20519 * @param {EventObject} e The mouse down event
20520 * @return {Object} The dragData
20522 getDragData : function(e){
20523 return Roo.dd.Registry.getHandleFromEvent(e);
20527 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20528 * this.dragData.ddel
20529 * @param {Number} x The x position of the click on the dragged object
20530 * @param {Number} y The y position of the click on the dragged object
20531 * @return {Boolean} true to continue the drag, false to cancel
20533 onInitDrag : function(x, y){
20534 this.proxy.update(this.dragData.ddel.cloneNode(true));
20535 this.onStartDrag(x, y);
20540 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20542 afterRepair : function(){
20544 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20546 this.dragging = false;
20550 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20551 * the XY of this.dragData.ddel
20552 * @param {EventObject} e The mouse up event
20553 * @return {Array} The xy location (e.g. [100, 200])
20555 getRepairXY : function(e){
20556 return Roo.Element.fly(this.dragData.ddel).getXY();
20560 * Ext JS Library 1.1.1
20561 * Copyright(c) 2006-2007, Ext JS, LLC.
20563 * Originally Released Under LGPL - original licence link has changed is not relivant.
20566 * <script type="text/javascript">
20569 * @class Roo.dd.DropZone
20570 * @extends Roo.dd.DropTarget
20571 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20572 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20574 * @param {String/HTMLElement/Element} el The container element
20575 * @param {Object} config
20577 Roo.dd.DropZone = function(el, config){
20578 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20581 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20583 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20584 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20585 * provide your own custom lookup.
20586 * @param {Event} e The event
20587 * @return {Object} data The custom data
20589 getTargetFromEvent : function(e){
20590 return Roo.dd.Registry.getTargetFromEvent(e);
20594 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20595 * that it has registered. This method has no default implementation and should be overridden to provide
20596 * node-specific processing if necessary.
20597 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20598 * {@link #getTargetFromEvent} for this node)
20599 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20600 * @param {Event} e The event
20601 * @param {Object} data An object containing arbitrary data supplied by the drag source
20603 onNodeEnter : function(n, dd, e, data){
20608 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20609 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20610 * overridden to provide the proper feedback.
20611 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20612 * {@link #getTargetFromEvent} for this node)
20613 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20614 * @param {Event} e The event
20615 * @param {Object} data An object containing arbitrary data supplied by the drag source
20616 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20617 * underlying {@link Roo.dd.StatusProxy} can be updated
20619 onNodeOver : function(n, dd, e, data){
20620 return this.dropAllowed;
20624 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20625 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20626 * node-specific processing if necessary.
20627 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20628 * {@link #getTargetFromEvent} for this node)
20629 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20630 * @param {Event} e The event
20631 * @param {Object} data An object containing arbitrary data supplied by the drag source
20633 onNodeOut : function(n, dd, e, data){
20638 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20639 * the drop node. The default implementation returns false, so it should be overridden to provide the
20640 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20641 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20642 * {@link #getTargetFromEvent} for this node)
20643 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20644 * @param {Event} e The event
20645 * @param {Object} data An object containing arbitrary data supplied by the drag source
20646 * @return {Boolean} True if the drop was valid, else false
20648 onNodeDrop : function(n, dd, e, data){
20653 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20654 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20655 * it should be overridden to provide the proper feedback if necessary.
20656 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20657 * @param {Event} e The event
20658 * @param {Object} data An object containing arbitrary data supplied by the drag source
20659 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20660 * underlying {@link Roo.dd.StatusProxy} can be updated
20662 onContainerOver : function(dd, e, data){
20663 return this.dropNotAllowed;
20667 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20668 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20669 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20670 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20671 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20672 * @param {Event} e The event
20673 * @param {Object} data An object containing arbitrary data supplied by the drag source
20674 * @return {Boolean} True if the drop was valid, else false
20676 onContainerDrop : function(dd, e, data){
20681 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20682 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20683 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20684 * you should override this method and provide a custom implementation.
20685 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20686 * @param {Event} e The event
20687 * @param {Object} data An object containing arbitrary data supplied by the drag source
20688 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20689 * underlying {@link Roo.dd.StatusProxy} can be updated
20691 notifyEnter : function(dd, e, data){
20692 return this.dropNotAllowed;
20696 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20697 * This method will be called on every mouse movement while the drag source is over the drop zone.
20698 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20699 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20700 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20701 * registered node, it will call {@link #onContainerOver}.
20702 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20703 * @param {Event} e The event
20704 * @param {Object} data An object containing arbitrary data supplied by the drag source
20705 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20706 * underlying {@link Roo.dd.StatusProxy} can be updated
20708 notifyOver : function(dd, e, data){
20709 var n = this.getTargetFromEvent(e);
20710 if(!n){ // not over valid drop target
20711 if(this.lastOverNode){
20712 this.onNodeOut(this.lastOverNode, dd, e, data);
20713 this.lastOverNode = null;
20715 return this.onContainerOver(dd, e, data);
20717 if(this.lastOverNode != n){
20718 if(this.lastOverNode){
20719 this.onNodeOut(this.lastOverNode, dd, e, data);
20721 this.onNodeEnter(n, dd, e, data);
20722 this.lastOverNode = n;
20724 return this.onNodeOver(n, dd, e, data);
20728 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20729 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20730 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20731 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20732 * @param {Event} e The event
20733 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20735 notifyOut : function(dd, e, data){
20736 if(this.lastOverNode){
20737 this.onNodeOut(this.lastOverNode, dd, e, data);
20738 this.lastOverNode = null;
20743 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20744 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20745 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20746 * otherwise it will call {@link #onContainerDrop}.
20747 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20748 * @param {Event} e The event
20749 * @param {Object} data An object containing arbitrary data supplied by the drag source
20750 * @return {Boolean} True if the drop was valid, else false
20752 notifyDrop : function(dd, e, data){
20753 if(this.lastOverNode){
20754 this.onNodeOut(this.lastOverNode, dd, e, data);
20755 this.lastOverNode = null;
20757 var n = this.getTargetFromEvent(e);
20759 this.onNodeDrop(n, dd, e, data) :
20760 this.onContainerDrop(dd, e, data);
20764 triggerCacheRefresh : function(){
20765 Roo.dd.DDM.refreshCache(this.groups);
20769 * Ext JS Library 1.1.1
20770 * Copyright(c) 2006-2007, Ext JS, LLC.
20772 * Originally Released Under LGPL - original licence link has changed is not relivant.
20775 * <script type="text/javascript">
20780 * @class Roo.data.SortTypes
20782 * Defines the default sorting (casting?) comparison functions used when sorting data.
20784 Roo.data.SortTypes = {
20786 * Default sort that does nothing
20787 * @param {Mixed} s The value being converted
20788 * @return {Mixed} The comparison value
20790 none : function(s){
20795 * The regular expression used to strip tags
20799 stripTagsRE : /<\/?[^>]+>/gi,
20802 * Strips all HTML tags to sort on text only
20803 * @param {Mixed} s The value being converted
20804 * @return {String} The comparison value
20806 asText : function(s){
20807 return String(s).replace(this.stripTagsRE, "");
20811 * Strips all HTML tags to sort on text only - Case insensitive
20812 * @param {Mixed} s The value being converted
20813 * @return {String} The comparison value
20815 asUCText : function(s){
20816 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20820 * Case insensitive string
20821 * @param {Mixed} s The value being converted
20822 * @return {String} The comparison value
20824 asUCString : function(s) {
20825 return String(s).toUpperCase();
20830 * @param {Mixed} s The value being converted
20831 * @return {Number} The comparison value
20833 asDate : function(s) {
20837 if(s instanceof Date){
20838 return s.getTime();
20840 return Date.parse(String(s));
20845 * @param {Mixed} s The value being converted
20846 * @return {Float} The comparison value
20848 asFloat : function(s) {
20849 var val = parseFloat(String(s).replace(/,/g, ""));
20850 if(isNaN(val)) val = 0;
20856 * @param {Mixed} s The value being converted
20857 * @return {Number} The comparison value
20859 asInt : function(s) {
20860 var val = parseInt(String(s).replace(/,/g, ""));
20861 if(isNaN(val)) val = 0;
20866 * Ext JS Library 1.1.1
20867 * Copyright(c) 2006-2007, Ext JS, LLC.
20869 * Originally Released Under LGPL - original licence link has changed is not relivant.
20872 * <script type="text/javascript">
20876 * @class Roo.data.Record
20877 * Instances of this class encapsulate both record <em>definition</em> information, and record
20878 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20879 * to access Records cached in an {@link Roo.data.Store} object.<br>
20881 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20882 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20885 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20887 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20888 * {@link #create}. The parameters are the same.
20889 * @param {Array} data An associative Array of data values keyed by the field name.
20890 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20891 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20892 * not specified an integer id is generated.
20894 Roo.data.Record = function(data, id){
20895 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20900 * Generate a constructor for a specific record layout.
20901 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20902 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20903 * Each field definition object may contain the following properties: <ul>
20904 * <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,
20905 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20906 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20907 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20908 * is being used, then this is a string containing the javascript expression to reference the data relative to
20909 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20910 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20911 * this may be omitted.</p></li>
20912 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20913 * <ul><li>auto (Default, implies no conversion)</li>
20918 * <li>date</li></ul></p></li>
20919 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20920 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20921 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20922 * by the Reader into an object that will be stored in the Record. It is passed the
20923 * following parameters:<ul>
20924 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20926 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20928 * <br>usage:<br><pre><code>
20929 var TopicRecord = Roo.data.Record.create(
20930 {name: 'title', mapping: 'topic_title'},
20931 {name: 'author', mapping: 'username'},
20932 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20933 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20934 {name: 'lastPoster', mapping: 'user2'},
20935 {name: 'excerpt', mapping: 'post_text'}
20938 var myNewRecord = new TopicRecord({
20939 title: 'Do my job please',
20942 lastPost: new Date(),
20943 lastPoster: 'Animal',
20944 excerpt: 'No way dude!'
20946 myStore.add(myNewRecord);
20951 Roo.data.Record.create = function(o){
20952 var f = function(){
20953 f.superclass.constructor.apply(this, arguments);
20955 Roo.extend(f, Roo.data.Record);
20956 var p = f.prototype;
20957 p.fields = new Roo.util.MixedCollection(false, function(field){
20960 for(var i = 0, len = o.length; i < len; i++){
20961 p.fields.add(new Roo.data.Field(o[i]));
20963 f.getField = function(name){
20964 return p.fields.get(name);
20969 Roo.data.Record.AUTO_ID = 1000;
20970 Roo.data.Record.EDIT = 'edit';
20971 Roo.data.Record.REJECT = 'reject';
20972 Roo.data.Record.COMMIT = 'commit';
20974 Roo.data.Record.prototype = {
20976 * Readonly flag - true if this record has been modified.
20985 join : function(store){
20986 this.store = store;
20990 * Set the named field to the specified value.
20991 * @param {String} name The name of the field to set.
20992 * @param {Object} value The value to set the field to.
20994 set : function(name, value){
20995 if(this.data[name] == value){
20999 if(!this.modified){
21000 this.modified = {};
21002 if(typeof this.modified[name] == 'undefined'){
21003 this.modified[name] = this.data[name];
21005 this.data[name] = value;
21006 if(!this.editing && this.store){
21007 this.store.afterEdit(this);
21012 * Get the value of the named field.
21013 * @param {String} name The name of the field to get the value of.
21014 * @return {Object} The value of the field.
21016 get : function(name){
21017 return this.data[name];
21021 beginEdit : function(){
21022 this.editing = true;
21023 this.modified = {};
21027 cancelEdit : function(){
21028 this.editing = false;
21029 delete this.modified;
21033 endEdit : function(){
21034 this.editing = false;
21035 if(this.dirty && this.store){
21036 this.store.afterEdit(this);
21041 * Usually called by the {@link Roo.data.Store} which owns the Record.
21042 * Rejects all changes made to the Record since either creation, or the last commit operation.
21043 * Modified fields are reverted to their original values.
21045 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21046 * of reject operations.
21048 reject : function(){
21049 var m = this.modified;
21051 if(typeof m[n] != "function"){
21052 this.data[n] = m[n];
21055 this.dirty = false;
21056 delete this.modified;
21057 this.editing = false;
21059 this.store.afterReject(this);
21064 * Usually called by the {@link Roo.data.Store} which owns the Record.
21065 * Commits all changes made to the Record since either creation, or the last commit operation.
21067 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21068 * of commit operations.
21070 commit : function(){
21071 this.dirty = false;
21072 delete this.modified;
21073 this.editing = false;
21075 this.store.afterCommit(this);
21080 hasError : function(){
21081 return this.error != null;
21085 clearError : function(){
21090 * Creates a copy of this record.
21091 * @param {String} id (optional) A new record id if you don't want to use this record's id
21094 copy : function(newId) {
21095 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21099 * Ext JS Library 1.1.1
21100 * Copyright(c) 2006-2007, Ext JS, LLC.
21102 * Originally Released Under LGPL - original licence link has changed is not relivant.
21105 * <script type="text/javascript">
21111 * @class Roo.data.Store
21112 * @extends Roo.util.Observable
21113 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21114 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21116 * 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
21117 * has no knowledge of the format of the data returned by the Proxy.<br>
21119 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21120 * instances from the data object. These records are cached and made available through accessor functions.
21122 * Creates a new Store.
21123 * @param {Object} config A config object containing the objects needed for the Store to access data,
21124 * and read the data into Records.
21126 Roo.data.Store = function(config){
21127 this.data = new Roo.util.MixedCollection(false);
21128 this.data.getKey = function(o){
21131 this.baseParams = {};
21133 this.paramNames = {
21138 "multisort" : "_multisort"
21141 if(config && config.data){
21142 this.inlineData = config.data;
21143 delete config.data;
21146 Roo.apply(this, config);
21148 if(this.reader){ // reader passed
21149 this.reader = Roo.factory(this.reader, Roo.data);
21150 this.reader.xmodule = this.xmodule || false;
21151 if(!this.recordType){
21152 this.recordType = this.reader.recordType;
21154 if(this.reader.onMetaChange){
21155 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21159 if(this.recordType){
21160 this.fields = this.recordType.prototype.fields;
21162 this.modified = [];
21166 * @event datachanged
21167 * Fires when the data cache has changed, and a widget which is using this Store
21168 * as a Record cache should refresh its view.
21169 * @param {Store} this
21171 datachanged : true,
21173 * @event metachange
21174 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21175 * @param {Store} this
21176 * @param {Object} meta The JSON metadata
21181 * Fires when Records have been added to the Store
21182 * @param {Store} this
21183 * @param {Roo.data.Record[]} records The array of Records added
21184 * @param {Number} index The index at which the record(s) were added
21189 * Fires when a Record has been removed from the Store
21190 * @param {Store} this
21191 * @param {Roo.data.Record} record The Record that was removed
21192 * @param {Number} index The index at which the record was removed
21197 * Fires when a Record has been updated
21198 * @param {Store} this
21199 * @param {Roo.data.Record} record The Record that was updated
21200 * @param {String} operation The update operation being performed. Value may be one of:
21202 Roo.data.Record.EDIT
21203 Roo.data.Record.REJECT
21204 Roo.data.Record.COMMIT
21210 * Fires when the data cache has been cleared.
21211 * @param {Store} this
21215 * @event beforeload
21216 * Fires before a request is made for a new data object. If the beforeload handler returns false
21217 * the load action will be canceled.
21218 * @param {Store} this
21219 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21223 * @event beforeloadadd
21224 * Fires after a new set of Records has been loaded.
21225 * @param {Store} this
21226 * @param {Roo.data.Record[]} records The Records that were loaded
21227 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21229 beforeloadadd : true,
21232 * Fires after a new set of Records has been loaded, before they are added to the store.
21233 * @param {Store} this
21234 * @param {Roo.data.Record[]} records The Records that were loaded
21235 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21236 * @params {Object} return from reader
21240 * @event loadexception
21241 * Fires if an exception occurs in the Proxy during loading.
21242 * Called with the signature of the Proxy's "loadexception" event.
21243 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21246 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21247 * @param {Object} load options
21248 * @param {Object} jsonData from your request (normally this contains the Exception)
21250 loadexception : true
21254 this.proxy = Roo.factory(this.proxy, Roo.data);
21255 this.proxy.xmodule = this.xmodule || false;
21256 this.relayEvents(this.proxy, ["loadexception"]);
21258 this.sortToggle = {};
21259 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21261 Roo.data.Store.superclass.constructor.call(this);
21263 if(this.inlineData){
21264 this.loadData(this.inlineData);
21265 delete this.inlineData;
21269 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21271 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21272 * without a remote query - used by combo/forms at present.
21276 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21279 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21282 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21283 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21286 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21287 * on any HTTP request
21290 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21293 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21297 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21298 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21300 remoteSort : false,
21303 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21304 * loaded or when a record is removed. (defaults to false).
21306 pruneModifiedRecords : false,
21309 lastOptions : null,
21312 * Add Records to the Store and fires the add event.
21313 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21315 add : function(records){
21316 records = [].concat(records);
21317 for(var i = 0, len = records.length; i < len; i++){
21318 records[i].join(this);
21320 var index = this.data.length;
21321 this.data.addAll(records);
21322 this.fireEvent("add", this, records, index);
21326 * Remove a Record from the Store and fires the remove event.
21327 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21329 remove : function(record){
21330 var index = this.data.indexOf(record);
21331 this.data.removeAt(index);
21332 if(this.pruneModifiedRecords){
21333 this.modified.remove(record);
21335 this.fireEvent("remove", this, record, index);
21339 * Remove all Records from the Store and fires the clear event.
21341 removeAll : function(){
21343 if(this.pruneModifiedRecords){
21344 this.modified = [];
21346 this.fireEvent("clear", this);
21350 * Inserts Records to the Store at the given index and fires the add event.
21351 * @param {Number} index The start index at which to insert the passed Records.
21352 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21354 insert : function(index, records){
21355 records = [].concat(records);
21356 for(var i = 0, len = records.length; i < len; i++){
21357 this.data.insert(index, records[i]);
21358 records[i].join(this);
21360 this.fireEvent("add", this, records, index);
21364 * Get the index within the cache of the passed Record.
21365 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21366 * @return {Number} The index of the passed Record. Returns -1 if not found.
21368 indexOf : function(record){
21369 return this.data.indexOf(record);
21373 * Get the index within the cache of the Record with the passed id.
21374 * @param {String} id The id of the Record to find.
21375 * @return {Number} The index of the Record. Returns -1 if not found.
21377 indexOfId : function(id){
21378 return this.data.indexOfKey(id);
21382 * Get the Record with the specified id.
21383 * @param {String} id The id of the Record to find.
21384 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21386 getById : function(id){
21387 return this.data.key(id);
21391 * Get the Record at the specified index.
21392 * @param {Number} index The index of the Record to find.
21393 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21395 getAt : function(index){
21396 return this.data.itemAt(index);
21400 * Returns a range of Records between specified indices.
21401 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21402 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21403 * @return {Roo.data.Record[]} An array of Records
21405 getRange : function(start, end){
21406 return this.data.getRange(start, end);
21410 storeOptions : function(o){
21411 o = Roo.apply({}, o);
21414 this.lastOptions = o;
21418 * Loads the Record cache from the configured Proxy using the configured Reader.
21420 * If using remote paging, then the first load call must specify the <em>start</em>
21421 * and <em>limit</em> properties in the options.params property to establish the initial
21422 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21424 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21425 * and this call will return before the new data has been loaded. Perform any post-processing
21426 * in a callback function, or in a "load" event handler.</strong>
21428 * @param {Object} options An object containing properties which control loading options:<ul>
21429 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21430 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21431 * passed the following arguments:<ul>
21432 * <li>r : Roo.data.Record[]</li>
21433 * <li>options: Options object from the load call</li>
21434 * <li>success: Boolean success indicator</li></ul></li>
21435 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21436 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21439 load : function(options){
21440 options = options || {};
21441 if(this.fireEvent("beforeload", this, options) !== false){
21442 this.storeOptions(options);
21443 var p = Roo.apply(options.params || {}, this.baseParams);
21444 // if meta was not loaded from remote source.. try requesting it.
21445 if (!this.reader.metaFromRemote) {
21446 p._requestMeta = 1;
21448 if(this.sortInfo && this.remoteSort){
21449 var pn = this.paramNames;
21450 p[pn["sort"]] = this.sortInfo.field;
21451 p[pn["dir"]] = this.sortInfo.direction;
21453 if (this.multiSort) {
21454 var pn = this.paramNames;
21455 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21458 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21463 * Reloads the Record cache from the configured Proxy using the configured Reader and
21464 * the options from the last load operation performed.
21465 * @param {Object} options (optional) An object containing properties which may override the options
21466 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21467 * the most recently used options are reused).
21469 reload : function(options){
21470 this.load(Roo.applyIf(options||{}, this.lastOptions));
21474 // Called as a callback by the Reader during a load operation.
21475 loadRecords : function(o, options, success){
21476 if(!o || success === false){
21477 if(success !== false){
21478 this.fireEvent("load", this, [], options, o);
21480 if(options.callback){
21481 options.callback.call(options.scope || this, [], options, false);
21485 // if data returned failure - throw an exception.
21486 if (o.success === false) {
21487 // show a message if no listener is registered.
21488 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21489 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21491 // loadmask wil be hooked into this..
21492 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21495 var r = o.records, t = o.totalRecords || r.length;
21497 this.fireEvent("beforeloadadd", this, r, options, o);
21499 if(!options || options.add !== true){
21500 if(this.pruneModifiedRecords){
21501 this.modified = [];
21503 for(var i = 0, len = r.length; i < len; i++){
21507 this.data = this.snapshot;
21508 delete this.snapshot;
21511 this.data.addAll(r);
21512 this.totalLength = t;
21514 this.fireEvent("datachanged", this);
21516 this.totalLength = Math.max(t, this.data.length+r.length);
21519 this.fireEvent("load", this, r, options, o);
21520 if(options.callback){
21521 options.callback.call(options.scope || this, r, options, true);
21527 * Loads data from a passed data block. A Reader which understands the format of the data
21528 * must have been configured in the constructor.
21529 * @param {Object} data The data block from which to read the Records. The format of the data expected
21530 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21531 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21533 loadData : function(o, append){
21534 var r = this.reader.readRecords(o);
21535 this.loadRecords(r, {add: append}, true);
21539 * Gets the number of cached records.
21541 * <em>If using paging, this may not be the total size of the dataset. If the data object
21542 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21543 * the data set size</em>
21545 getCount : function(){
21546 return this.data.length || 0;
21550 * Gets the total number of records in the dataset as returned by the server.
21552 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21553 * the dataset size</em>
21555 getTotalCount : function(){
21556 return this.totalLength || 0;
21560 * Returns the sort state of the Store as an object with two properties:
21562 field {String} The name of the field by which the Records are sorted
21563 direction {String} The sort order, "ASC" or "DESC"
21566 getSortState : function(){
21567 return this.sortInfo;
21571 applySort : function(){
21572 if(this.sortInfo && !this.remoteSort){
21573 var s = this.sortInfo, f = s.field;
21574 var st = this.fields.get(f).sortType;
21575 var fn = function(r1, r2){
21576 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21577 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21579 this.data.sort(s.direction, fn);
21580 if(this.snapshot && this.snapshot != this.data){
21581 this.snapshot.sort(s.direction, fn);
21587 * Sets the default sort column and order to be used by the next load operation.
21588 * @param {String} fieldName The name of the field to sort by.
21589 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21591 setDefaultSort : function(field, dir){
21592 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21596 * Sort the Records.
21597 * If remote sorting is used, the sort is performed on the server, and the cache is
21598 * reloaded. If local sorting is used, the cache is sorted internally.
21599 * @param {String} fieldName The name of the field to sort by.
21600 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21602 sort : function(fieldName, dir){
21603 var f = this.fields.get(fieldName);
21605 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21607 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21608 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21613 this.sortToggle[f.name] = dir;
21614 this.sortInfo = {field: f.name, direction: dir};
21615 if(!this.remoteSort){
21617 this.fireEvent("datachanged", this);
21619 this.load(this.lastOptions);
21624 * Calls the specified function for each of the Records in the cache.
21625 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21626 * Returning <em>false</em> aborts and exits the iteration.
21627 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21629 each : function(fn, scope){
21630 this.data.each(fn, scope);
21634 * Gets all records modified since the last commit. Modified records are persisted across load operations
21635 * (e.g., during paging).
21636 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21638 getModifiedRecords : function(){
21639 return this.modified;
21643 createFilterFn : function(property, value, anyMatch){
21644 if(!value.exec){ // not a regex
21645 value = String(value);
21646 if(value.length == 0){
21649 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21651 return function(r){
21652 return value.test(r.data[property]);
21657 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21658 * @param {String} property A field on your records
21659 * @param {Number} start The record index to start at (defaults to 0)
21660 * @param {Number} end The last record index to include (defaults to length - 1)
21661 * @return {Number} The sum
21663 sum : function(property, start, end){
21664 var rs = this.data.items, v = 0;
21665 start = start || 0;
21666 end = (end || end === 0) ? end : rs.length-1;
21668 for(var i = start; i <= end; i++){
21669 v += (rs[i].data[property] || 0);
21675 * Filter the records by a specified property.
21676 * @param {String} field A field on your records
21677 * @param {String/RegExp} value Either a string that the field
21678 * should start with or a RegExp to test against the field
21679 * @param {Boolean} anyMatch True to match any part not just the beginning
21681 filter : function(property, value, anyMatch){
21682 var fn = this.createFilterFn(property, value, anyMatch);
21683 return fn ? this.filterBy(fn) : this.clearFilter();
21687 * Filter by a function. The specified function will be called with each
21688 * record in this data source. If the function returns true the record is included,
21689 * otherwise it is filtered.
21690 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21691 * @param {Object} scope (optional) The scope of the function (defaults to this)
21693 filterBy : function(fn, scope){
21694 this.snapshot = this.snapshot || this.data;
21695 this.data = this.queryBy(fn, scope||this);
21696 this.fireEvent("datachanged", this);
21700 * Query the records by a specified property.
21701 * @param {String} field A field on your records
21702 * @param {String/RegExp} value Either a string that the field
21703 * should start with or a RegExp to test against the field
21704 * @param {Boolean} anyMatch True to match any part not just the beginning
21705 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21707 query : function(property, value, anyMatch){
21708 var fn = this.createFilterFn(property, value, anyMatch);
21709 return fn ? this.queryBy(fn) : this.data.clone();
21713 * Query by a function. The specified function will be called with each
21714 * record in this data source. If the function returns true the record is included
21716 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21717 * @param {Object} scope (optional) The scope of the function (defaults to this)
21718 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21720 queryBy : function(fn, scope){
21721 var data = this.snapshot || this.data;
21722 return data.filterBy(fn, scope||this);
21726 * Collects unique values for a particular dataIndex from this store.
21727 * @param {String} dataIndex The property to collect
21728 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21729 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21730 * @return {Array} An array of the unique values
21732 collect : function(dataIndex, allowNull, bypassFilter){
21733 var d = (bypassFilter === true && this.snapshot) ?
21734 this.snapshot.items : this.data.items;
21735 var v, sv, r = [], l = {};
21736 for(var i = 0, len = d.length; i < len; i++){
21737 v = d[i].data[dataIndex];
21739 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21748 * Revert to a view of the Record cache with no filtering applied.
21749 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21751 clearFilter : function(suppressEvent){
21752 if(this.snapshot && this.snapshot != this.data){
21753 this.data = this.snapshot;
21754 delete this.snapshot;
21755 if(suppressEvent !== true){
21756 this.fireEvent("datachanged", this);
21762 afterEdit : function(record){
21763 if(this.modified.indexOf(record) == -1){
21764 this.modified.push(record);
21766 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21770 afterReject : function(record){
21771 this.modified.remove(record);
21772 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21776 afterCommit : function(record){
21777 this.modified.remove(record);
21778 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21782 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21783 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21785 commitChanges : function(){
21786 var m = this.modified.slice(0);
21787 this.modified = [];
21788 for(var i = 0, len = m.length; i < len; i++){
21794 * Cancel outstanding changes on all changed records.
21796 rejectChanges : function(){
21797 var m = this.modified.slice(0);
21798 this.modified = [];
21799 for(var i = 0, len = m.length; i < len; i++){
21804 onMetaChange : function(meta, rtype, o){
21805 this.recordType = rtype;
21806 this.fields = rtype.prototype.fields;
21807 delete this.snapshot;
21808 this.sortInfo = meta.sortInfo || this.sortInfo;
21809 this.modified = [];
21810 this.fireEvent('metachange', this, this.reader.meta);
21813 moveIndex : function(data, type)
21815 var index = this.indexOf(data);
21817 var newIndex = index + type;
21821 this.insert(newIndex, data);
21826 * Ext JS Library 1.1.1
21827 * Copyright(c) 2006-2007, Ext JS, LLC.
21829 * Originally Released Under LGPL - original licence link has changed is not relivant.
21832 * <script type="text/javascript">
21836 * @class Roo.data.SimpleStore
21837 * @extends Roo.data.Store
21838 * Small helper class to make creating Stores from Array data easier.
21839 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21840 * @cfg {Array} fields An array of field definition objects, or field name strings.
21841 * @cfg {Array} data The multi-dimensional array of data
21843 * @param {Object} config
21845 Roo.data.SimpleStore = function(config){
21846 Roo.data.SimpleStore.superclass.constructor.call(this, {
21848 reader: new Roo.data.ArrayReader({
21851 Roo.data.Record.create(config.fields)
21853 proxy : new Roo.data.MemoryProxy(config.data)
21857 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21859 * Ext JS Library 1.1.1
21860 * Copyright(c) 2006-2007, Ext JS, LLC.
21862 * Originally Released Under LGPL - original licence link has changed is not relivant.
21865 * <script type="text/javascript">
21870 * @extends Roo.data.Store
21871 * @class Roo.data.JsonStore
21872 * Small helper class to make creating Stores for JSON data easier. <br/>
21874 var store = new Roo.data.JsonStore({
21875 url: 'get-images.php',
21877 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21880 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21881 * JsonReader and HttpProxy (unless inline data is provided).</b>
21882 * @cfg {Array} fields An array of field definition objects, or field name strings.
21884 * @param {Object} config
21886 Roo.data.JsonStore = function(c){
21887 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21888 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21889 reader: new Roo.data.JsonReader(c, c.fields)
21892 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21894 * Ext JS Library 1.1.1
21895 * Copyright(c) 2006-2007, Ext JS, LLC.
21897 * Originally Released Under LGPL - original licence link has changed is not relivant.
21900 * <script type="text/javascript">
21904 Roo.data.Field = function(config){
21905 if(typeof config == "string"){
21906 config = {name: config};
21908 Roo.apply(this, config);
21911 this.type = "auto";
21914 var st = Roo.data.SortTypes;
21915 // named sortTypes are supported, here we look them up
21916 if(typeof this.sortType == "string"){
21917 this.sortType = st[this.sortType];
21920 // set default sortType for strings and dates
21921 if(!this.sortType){
21924 this.sortType = st.asUCString;
21927 this.sortType = st.asDate;
21930 this.sortType = st.none;
21935 var stripRe = /[\$,%]/g;
21937 // prebuilt conversion function for this field, instead of
21938 // switching every time we're reading a value
21940 var cv, dateFormat = this.dateFormat;
21945 cv = function(v){ return v; };
21948 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
21952 return v !== undefined && v !== null && v !== '' ?
21953 parseInt(String(v).replace(stripRe, ""), 10) : '';
21958 return v !== undefined && v !== null && v !== '' ?
21959 parseFloat(String(v).replace(stripRe, ""), 10) : '';
21964 cv = function(v){ return v === true || v === "true" || v == 1; };
21971 if(v instanceof Date){
21975 if(dateFormat == "timestamp"){
21976 return new Date(v*1000);
21978 return Date.parseDate(v, dateFormat);
21980 var parsed = Date.parse(v);
21981 return parsed ? new Date(parsed) : null;
21990 Roo.data.Field.prototype = {
21998 * Ext JS Library 1.1.1
21999 * Copyright(c) 2006-2007, Ext JS, LLC.
22001 * Originally Released Under LGPL - original licence link has changed is not relivant.
22004 * <script type="text/javascript">
22007 // Base class for reading structured data from a data source. This class is intended to be
22008 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
22011 * @class Roo.data.DataReader
22012 * Base class for reading structured data from a data source. This class is intended to be
22013 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
22016 Roo.data.DataReader = function(meta, recordType){
22020 this.recordType = recordType instanceof Array ?
22021 Roo.data.Record.create(recordType) : recordType;
22024 Roo.data.DataReader.prototype = {
22026 * Create an empty record
22027 * @param {Object} data (optional) - overlay some values
22028 * @return {Roo.data.Record} record created.
22030 newRow : function(d) {
22032 this.recordType.prototype.fields.each(function(c) {
22034 case 'int' : da[c.name] = 0; break;
22035 case 'date' : da[c.name] = new Date(); break;
22036 case 'float' : da[c.name] = 0.0; break;
22037 case 'boolean' : da[c.name] = false; break;
22038 default : da[c.name] = ""; break;
22042 return new this.recordType(Roo.apply(da, d));
22047 * Ext JS Library 1.1.1
22048 * Copyright(c) 2006-2007, Ext JS, LLC.
22050 * Originally Released Under LGPL - original licence link has changed is not relivant.
22053 * <script type="text/javascript">
22057 * @class Roo.data.DataProxy
22058 * @extends Roo.data.Observable
22059 * This class is an abstract base class for implementations which provide retrieval of
22060 * unformatted data objects.<br>
22062 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22063 * (of the appropriate type which knows how to parse the data object) to provide a block of
22064 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22066 * Custom implementations must implement the load method as described in
22067 * {@link Roo.data.HttpProxy#load}.
22069 Roo.data.DataProxy = function(){
22072 * @event beforeload
22073 * Fires before a network request is made to retrieve a data object.
22074 * @param {Object} This DataProxy object.
22075 * @param {Object} params The params parameter to the load function.
22080 * Fires before the load method's callback is called.
22081 * @param {Object} This DataProxy object.
22082 * @param {Object} o The data object.
22083 * @param {Object} arg The callback argument object passed to the load function.
22087 * @event loadexception
22088 * Fires if an Exception occurs during data retrieval.
22089 * @param {Object} This DataProxy object.
22090 * @param {Object} o The data object.
22091 * @param {Object} arg The callback argument object passed to the load function.
22092 * @param {Object} e The Exception.
22094 loadexception : true
22096 Roo.data.DataProxy.superclass.constructor.call(this);
22099 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22102 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22106 * Ext JS Library 1.1.1
22107 * Copyright(c) 2006-2007, Ext JS, LLC.
22109 * Originally Released Under LGPL - original licence link has changed is not relivant.
22112 * <script type="text/javascript">
22115 * @class Roo.data.MemoryProxy
22116 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22117 * to the Reader when its load method is called.
22119 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22121 Roo.data.MemoryProxy = function(data){
22125 Roo.data.MemoryProxy.superclass.constructor.call(this);
22129 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22131 * Load data from the requested source (in this case an in-memory
22132 * data object passed to the constructor), read the data object into
22133 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22134 * process that block using the passed callback.
22135 * @param {Object} params This parameter is not used by the MemoryProxy class.
22136 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22137 * object into a block of Roo.data.Records.
22138 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22139 * The function must be passed <ul>
22140 * <li>The Record block object</li>
22141 * <li>The "arg" argument from the load function</li>
22142 * <li>A boolean success indicator</li>
22144 * @param {Object} scope The scope in which to call the callback
22145 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22147 load : function(params, reader, callback, scope, arg){
22148 params = params || {};
22151 result = reader.readRecords(this.data);
22153 this.fireEvent("loadexception", this, arg, null, e);
22154 callback.call(scope, null, arg, false);
22157 callback.call(scope, result, arg, true);
22161 update : function(params, records){
22166 * Ext JS Library 1.1.1
22167 * Copyright(c) 2006-2007, Ext JS, LLC.
22169 * Originally Released Under LGPL - original licence link has changed is not relivant.
22172 * <script type="text/javascript">
22175 * @class Roo.data.HttpProxy
22176 * @extends Roo.data.DataProxy
22177 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22178 * configured to reference a certain URL.<br><br>
22180 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22181 * from which the running page was served.<br><br>
22183 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22185 * Be aware that to enable the browser to parse an XML document, the server must set
22186 * the Content-Type header in the HTTP response to "text/xml".
22188 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22189 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22190 * will be used to make the request.
22192 Roo.data.HttpProxy = function(conn){
22193 Roo.data.HttpProxy.superclass.constructor.call(this);
22194 // is conn a conn config or a real conn?
22196 this.useAjax = !conn || !conn.events;
22200 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22201 // thse are take from connection...
22204 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22207 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22208 * extra parameters to each request made by this object. (defaults to undefined)
22211 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22212 * to each request made by this object. (defaults to undefined)
22215 * @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)
22218 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22221 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22227 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22231 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22232 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22233 * a finer-grained basis than the DataProxy events.
22235 getConnection : function(){
22236 return this.useAjax ? Roo.Ajax : this.conn;
22240 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22241 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22242 * process that block using the passed callback.
22243 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22244 * for the request to the remote server.
22245 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22246 * object into a block of Roo.data.Records.
22247 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22248 * The function must be passed <ul>
22249 * <li>The Record block object</li>
22250 * <li>The "arg" argument from the load function</li>
22251 * <li>A boolean success indicator</li>
22253 * @param {Object} scope The scope in which to call the callback
22254 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22256 load : function(params, reader, callback, scope, arg){
22257 if(this.fireEvent("beforeload", this, params) !== false){
22259 params : params || {},
22261 callback : callback,
22266 callback : this.loadResponse,
22270 Roo.applyIf(o, this.conn);
22271 if(this.activeRequest){
22272 Roo.Ajax.abort(this.activeRequest);
22274 this.activeRequest = Roo.Ajax.request(o);
22276 this.conn.request(o);
22279 callback.call(scope||this, null, arg, false);
22284 loadResponse : function(o, success, response){
22285 delete this.activeRequest;
22287 this.fireEvent("loadexception", this, o, response);
22288 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22293 result = o.reader.read(response);
22295 this.fireEvent("loadexception", this, o, response, e);
22296 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22300 this.fireEvent("load", this, o, o.request.arg);
22301 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22305 update : function(dataSet){
22310 updateResponse : function(dataSet){
22315 * Ext JS Library 1.1.1
22316 * Copyright(c) 2006-2007, Ext JS, LLC.
22318 * Originally Released Under LGPL - original licence link has changed is not relivant.
22321 * <script type="text/javascript">
22325 * @class Roo.data.ScriptTagProxy
22326 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22327 * other than the originating domain of the running page.<br><br>
22329 * <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
22330 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22332 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22333 * source code that is used as the source inside a <script> tag.<br><br>
22335 * In order for the browser to process the returned data, the server must wrap the data object
22336 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22337 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22338 * depending on whether the callback name was passed:
22341 boolean scriptTag = false;
22342 String cb = request.getParameter("callback");
22345 response.setContentType("text/javascript");
22347 response.setContentType("application/x-json");
22349 Writer out = response.getWriter();
22351 out.write(cb + "(");
22353 out.print(dataBlock.toJsonString());
22360 * @param {Object} config A configuration object.
22362 Roo.data.ScriptTagProxy = function(config){
22363 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22364 Roo.apply(this, config);
22365 this.head = document.getElementsByTagName("head")[0];
22368 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22370 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22372 * @cfg {String} url The URL from which to request the data object.
22375 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22379 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22380 * the server the name of the callback function set up by the load call to process the returned data object.
22381 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22382 * javascript output which calls this named function passing the data object as its only parameter.
22384 callbackParam : "callback",
22386 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22387 * name to the request.
22392 * Load data from the configured URL, read the data object into
22393 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22394 * process that block using the passed callback.
22395 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22396 * for the request to the remote server.
22397 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22398 * object into a block of Roo.data.Records.
22399 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22400 * The function must be passed <ul>
22401 * <li>The Record block object</li>
22402 * <li>The "arg" argument from the load function</li>
22403 * <li>A boolean success indicator</li>
22405 * @param {Object} scope The scope in which to call the callback
22406 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22408 load : function(params, reader, callback, scope, arg){
22409 if(this.fireEvent("beforeload", this, params) !== false){
22411 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22413 var url = this.url;
22414 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22416 url += "&_dc=" + (new Date().getTime());
22418 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22421 cb : "stcCallback"+transId,
22422 scriptId : "stcScript"+transId,
22426 callback : callback,
22432 window[trans.cb] = function(o){
22433 conn.handleResponse(o, trans);
22436 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22438 if(this.autoAbort !== false){
22442 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22444 var script = document.createElement("script");
22445 script.setAttribute("src", url);
22446 script.setAttribute("type", "text/javascript");
22447 script.setAttribute("id", trans.scriptId);
22448 this.head.appendChild(script);
22450 this.trans = trans;
22452 callback.call(scope||this, null, arg, false);
22457 isLoading : function(){
22458 return this.trans ? true : false;
22462 * Abort the current server request.
22464 abort : function(){
22465 if(this.isLoading()){
22466 this.destroyTrans(this.trans);
22471 destroyTrans : function(trans, isLoaded){
22472 this.head.removeChild(document.getElementById(trans.scriptId));
22473 clearTimeout(trans.timeoutId);
22475 window[trans.cb] = undefined;
22477 delete window[trans.cb];
22480 // if hasn't been loaded, wait for load to remove it to prevent script error
22481 window[trans.cb] = function(){
22482 window[trans.cb] = undefined;
22484 delete window[trans.cb];
22491 handleResponse : function(o, trans){
22492 this.trans = false;
22493 this.destroyTrans(trans, true);
22496 result = trans.reader.readRecords(o);
22498 this.fireEvent("loadexception", this, o, trans.arg, e);
22499 trans.callback.call(trans.scope||window, null, trans.arg, false);
22502 this.fireEvent("load", this, o, trans.arg);
22503 trans.callback.call(trans.scope||window, result, trans.arg, true);
22507 handleFailure : function(trans){
22508 this.trans = false;
22509 this.destroyTrans(trans, false);
22510 this.fireEvent("loadexception", this, null, trans.arg);
22511 trans.callback.call(trans.scope||window, null, trans.arg, false);
22515 * Ext JS Library 1.1.1
22516 * Copyright(c) 2006-2007, Ext JS, LLC.
22518 * Originally Released Under LGPL - original licence link has changed is not relivant.
22521 * <script type="text/javascript">
22525 * @class Roo.data.JsonReader
22526 * @extends Roo.data.DataReader
22527 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22528 * based on mappings in a provided Roo.data.Record constructor.
22530 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22531 * in the reply previously.
22536 var RecordDef = Roo.data.Record.create([
22537 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22538 {name: 'occupation'} // This field will use "occupation" as the mapping.
22540 var myReader = new Roo.data.JsonReader({
22541 totalProperty: "results", // The property which contains the total dataset size (optional)
22542 root: "rows", // The property which contains an Array of row objects
22543 id: "id" // The property within each row object that provides an ID for the record (optional)
22547 * This would consume a JSON file like this:
22549 { 'results': 2, 'rows': [
22550 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22551 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22554 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22555 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22556 * paged from the remote server.
22557 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22558 * @cfg {String} root name of the property which contains the Array of row objects.
22559 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22561 * Create a new JsonReader
22562 * @param {Object} meta Metadata configuration options
22563 * @param {Object} recordType Either an Array of field definition objects,
22564 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22566 Roo.data.JsonReader = function(meta, recordType){
22569 // set some defaults:
22570 Roo.applyIf(meta, {
22571 totalProperty: 'total',
22572 successProperty : 'success',
22577 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22579 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22582 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22583 * Used by Store query builder to append _requestMeta to params.
22586 metaFromRemote : false,
22588 * This method is only used by a DataProxy which has retrieved data from a remote server.
22589 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22590 * @return {Object} data A data block which is used by an Roo.data.Store object as
22591 * a cache of Roo.data.Records.
22593 read : function(response){
22594 var json = response.responseText;
22596 var o = /* eval:var:o */ eval("("+json+")");
22598 throw {message: "JsonReader.read: Json object not found"};
22604 this.metaFromRemote = true;
22605 this.meta = o.metaData;
22606 this.recordType = Roo.data.Record.create(o.metaData.fields);
22607 this.onMetaChange(this.meta, this.recordType, o);
22609 return this.readRecords(o);
22612 // private function a store will implement
22613 onMetaChange : function(meta, recordType, o){
22620 simpleAccess: function(obj, subsc) {
22627 getJsonAccessor: function(){
22629 return function(expr) {
22631 return(re.test(expr))
22632 ? new Function("obj", "return obj." + expr)
22637 return Roo.emptyFn;
22642 * Create a data block containing Roo.data.Records from an XML document.
22643 * @param {Object} o An object which contains an Array of row objects in the property specified
22644 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22645 * which contains the total size of the dataset.
22646 * @return {Object} data A data block which is used by an Roo.data.Store object as
22647 * a cache of Roo.data.Records.
22649 readRecords : function(o){
22651 * After any data loads, the raw JSON data is available for further custom processing.
22655 var s = this.meta, Record = this.recordType,
22656 f = Record.prototype.fields, fi = f.items, fl = f.length;
22658 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22660 if(s.totalProperty) {
22661 this.getTotal = this.getJsonAccessor(s.totalProperty);
22663 if(s.successProperty) {
22664 this.getSuccess = this.getJsonAccessor(s.successProperty);
22666 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22668 var g = this.getJsonAccessor(s.id);
22669 this.getId = function(rec) {
22671 return (r === undefined || r === "") ? null : r;
22674 this.getId = function(){return null;};
22677 for(var jj = 0; jj < fl; jj++){
22679 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22680 this.ef[jj] = this.getJsonAccessor(map);
22684 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22685 if(s.totalProperty){
22686 var vt = parseInt(this.getTotal(o), 10);
22691 if(s.successProperty){
22692 var vs = this.getSuccess(o);
22693 if(vs === false || vs === 'false'){
22698 for(var i = 0; i < c; i++){
22701 var id = this.getId(n);
22702 for(var j = 0; j < fl; j++){
22704 var v = this.ef[j](n);
22706 Roo.log('missing convert for ' + f.name);
22710 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22712 var record = new Record(values, id);
22714 records[i] = record;
22720 totalRecords : totalRecords
22725 * Ext JS Library 1.1.1
22726 * Copyright(c) 2006-2007, Ext JS, LLC.
22728 * Originally Released Under LGPL - original licence link has changed is not relivant.
22731 * <script type="text/javascript">
22735 * @class Roo.data.XmlReader
22736 * @extends Roo.data.DataReader
22737 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22738 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22740 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22741 * header in the HTTP response must be set to "text/xml".</em>
22745 var RecordDef = Roo.data.Record.create([
22746 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22747 {name: 'occupation'} // This field will use "occupation" as the mapping.
22749 var myReader = new Roo.data.XmlReader({
22750 totalRecords: "results", // The element which contains the total dataset size (optional)
22751 record: "row", // The repeated element which contains row information
22752 id: "id" // The element within the row that provides an ID for the record (optional)
22756 * This would consume an XML file like this:
22760 <results>2</results>
22763 <name>Bill</name>
22764 <occupation>Gardener</occupation>
22768 <name>Ben</name>
22769 <occupation>Horticulturalist</occupation>
22773 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22774 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22775 * paged from the remote server.
22776 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22777 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22778 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22779 * a record identifier value.
22781 * Create a new XmlReader
22782 * @param {Object} meta Metadata configuration options
22783 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22784 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22785 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22787 Roo.data.XmlReader = function(meta, recordType){
22789 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22791 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22793 * This method is only used by a DataProxy which has retrieved data from a remote server.
22794 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22795 * to contain a method called 'responseXML' that returns an XML document object.
22796 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22797 * a cache of Roo.data.Records.
22799 read : function(response){
22800 var doc = response.responseXML;
22802 throw {message: "XmlReader.read: XML Document not available"};
22804 return this.readRecords(doc);
22808 * Create a data block containing Roo.data.Records from an XML document.
22809 * @param {Object} doc A parsed XML document.
22810 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22811 * a cache of Roo.data.Records.
22813 readRecords : function(doc){
22815 * After any data loads/reads, the raw XML Document is available for further custom processing.
22816 * @type XMLDocument
22818 this.xmlData = doc;
22819 var root = doc.documentElement || doc;
22820 var q = Roo.DomQuery;
22821 var recordType = this.recordType, fields = recordType.prototype.fields;
22822 var sid = this.meta.id;
22823 var totalRecords = 0, success = true;
22824 if(this.meta.totalRecords){
22825 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22828 if(this.meta.success){
22829 var sv = q.selectValue(this.meta.success, root, true);
22830 success = sv !== false && sv !== 'false';
22833 var ns = q.select(this.meta.record, root);
22834 for(var i = 0, len = ns.length; i < len; i++) {
22837 var id = sid ? q.selectValue(sid, n) : undefined;
22838 for(var j = 0, jlen = fields.length; j < jlen; j++){
22839 var f = fields.items[j];
22840 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22842 values[f.name] = v;
22844 var record = new recordType(values, id);
22846 records[records.length] = record;
22852 totalRecords : totalRecords || records.length
22857 * Ext JS Library 1.1.1
22858 * Copyright(c) 2006-2007, Ext JS, LLC.
22860 * Originally Released Under LGPL - original licence link has changed is not relivant.
22863 * <script type="text/javascript">
22867 * @class Roo.data.ArrayReader
22868 * @extends Roo.data.DataReader
22869 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22870 * Each element of that Array represents a row of data fields. The
22871 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22872 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22876 var RecordDef = Roo.data.Record.create([
22877 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22878 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22880 var myReader = new Roo.data.ArrayReader({
22881 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22885 * This would consume an Array like this:
22887 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22889 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22891 * Create a new JsonReader
22892 * @param {Object} meta Metadata configuration options.
22893 * @param {Object} recordType Either an Array of field definition objects
22894 * as specified to {@link Roo.data.Record#create},
22895 * or an {@link Roo.data.Record} object
22896 * created using {@link Roo.data.Record#create}.
22898 Roo.data.ArrayReader = function(meta, recordType){
22899 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22902 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22904 * Create a data block containing Roo.data.Records from an XML document.
22905 * @param {Object} o An Array of row objects which represents the dataset.
22906 * @return {Object} data A data block which is used by an Roo.data.Store object as
22907 * a cache of Roo.data.Records.
22909 readRecords : function(o){
22910 var sid = this.meta ? this.meta.id : null;
22911 var recordType = this.recordType, fields = recordType.prototype.fields;
22914 for(var i = 0; i < root.length; i++){
22917 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22918 for(var j = 0, jlen = fields.length; j < jlen; j++){
22919 var f = fields.items[j];
22920 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22921 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22923 values[f.name] = v;
22925 var record = new recordType(values, id);
22927 records[records.length] = record;
22931 totalRecords : records.length
22936 * Ext JS Library 1.1.1
22937 * Copyright(c) 2006-2007, Ext JS, LLC.
22939 * Originally Released Under LGPL - original licence link has changed is not relivant.
22942 * <script type="text/javascript">
22947 * @class Roo.data.Tree
22948 * @extends Roo.util.Observable
22949 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
22950 * in the tree have most standard DOM functionality.
22952 * @param {Node} root (optional) The root node
22954 Roo.data.Tree = function(root){
22955 this.nodeHash = {};
22957 * The root node for this tree
22962 this.setRootNode(root);
22967 * Fires when a new child node is appended to a node in this tree.
22968 * @param {Tree} tree The owner tree
22969 * @param {Node} parent The parent node
22970 * @param {Node} node The newly appended node
22971 * @param {Number} index The index of the newly appended node
22976 * Fires when a child node is removed from a node in this tree.
22977 * @param {Tree} tree The owner tree
22978 * @param {Node} parent The parent node
22979 * @param {Node} node The child node removed
22984 * Fires when a node is moved to a new location in the tree
22985 * @param {Tree} tree The owner tree
22986 * @param {Node} node The node moved
22987 * @param {Node} oldParent The old parent of this node
22988 * @param {Node} newParent The new parent of this node
22989 * @param {Number} index The index it was moved to
22994 * Fires when a new child node is inserted in a node in this tree.
22995 * @param {Tree} tree The owner tree
22996 * @param {Node} parent The parent node
22997 * @param {Node} node The child node inserted
22998 * @param {Node} refNode The child node the node was inserted before
23002 * @event beforeappend
23003 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
23004 * @param {Tree} tree The owner tree
23005 * @param {Node} parent The parent node
23006 * @param {Node} node The child node to be appended
23008 "beforeappend" : true,
23010 * @event beforeremove
23011 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
23012 * @param {Tree} tree The owner tree
23013 * @param {Node} parent The parent node
23014 * @param {Node} node The child node to be removed
23016 "beforeremove" : true,
23018 * @event beforemove
23019 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
23020 * @param {Tree} tree The owner tree
23021 * @param {Node} node The node being moved
23022 * @param {Node} oldParent The parent of the node
23023 * @param {Node} newParent The new parent the node is moving to
23024 * @param {Number} index The index it is being moved to
23026 "beforemove" : true,
23028 * @event beforeinsert
23029 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
23030 * @param {Tree} tree The owner tree
23031 * @param {Node} parent The parent node
23032 * @param {Node} node The child node to be inserted
23033 * @param {Node} refNode The child node the node is being inserted before
23035 "beforeinsert" : true
23038 Roo.data.Tree.superclass.constructor.call(this);
23041 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
23042 pathSeparator: "/",
23044 proxyNodeEvent : function(){
23045 return this.fireEvent.apply(this, arguments);
23049 * Returns the root node for this tree.
23052 getRootNode : function(){
23057 * Sets the root node for this tree.
23058 * @param {Node} node
23061 setRootNode : function(node){
23063 node.ownerTree = this;
23064 node.isRoot = true;
23065 this.registerNode(node);
23070 * Gets a node in this tree by its id.
23071 * @param {String} id
23074 getNodeById : function(id){
23075 return this.nodeHash[id];
23078 registerNode : function(node){
23079 this.nodeHash[node.id] = node;
23082 unregisterNode : function(node){
23083 delete this.nodeHash[node.id];
23086 toString : function(){
23087 return "[Tree"+(this.id?" "+this.id:"")+"]";
23092 * @class Roo.data.Node
23093 * @extends Roo.util.Observable
23094 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23095 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23097 * @param {Object} attributes The attributes/config for the node
23099 Roo.data.Node = function(attributes){
23101 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23104 this.attributes = attributes || {};
23105 this.leaf = this.attributes.leaf;
23107 * The node id. @type String
23109 this.id = this.attributes.id;
23111 this.id = Roo.id(null, "ynode-");
23112 this.attributes.id = this.id;
23117 * All child nodes of this node. @type Array
23119 this.childNodes = [];
23120 if(!this.childNodes.indexOf){ // indexOf is a must
23121 this.childNodes.indexOf = function(o){
23122 for(var i = 0, len = this.length; i < len; i++){
23131 * The parent node for this node. @type Node
23133 this.parentNode = null;
23135 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23137 this.firstChild = null;
23139 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23141 this.lastChild = null;
23143 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23145 this.previousSibling = null;
23147 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23149 this.nextSibling = null;
23154 * Fires when a new child node is appended
23155 * @param {Tree} tree The owner tree
23156 * @param {Node} this This node
23157 * @param {Node} node The newly appended node
23158 * @param {Number} index The index of the newly appended node
23163 * Fires when a child node is removed
23164 * @param {Tree} tree The owner tree
23165 * @param {Node} this This node
23166 * @param {Node} node The removed node
23171 * Fires when this node is moved to a new location in the tree
23172 * @param {Tree} tree The owner tree
23173 * @param {Node} this This node
23174 * @param {Node} oldParent The old parent of this node
23175 * @param {Node} newParent The new parent of this node
23176 * @param {Number} index The index it was moved to
23181 * Fires when a new child node is inserted.
23182 * @param {Tree} tree The owner tree
23183 * @param {Node} this This node
23184 * @param {Node} node The child node inserted
23185 * @param {Node} refNode The child node the node was inserted before
23189 * @event beforeappend
23190 * Fires before a new child is appended, return false to cancel the append.
23191 * @param {Tree} tree The owner tree
23192 * @param {Node} this This node
23193 * @param {Node} node The child node to be appended
23195 "beforeappend" : true,
23197 * @event beforeremove
23198 * Fires before a child is removed, return false to cancel the remove.
23199 * @param {Tree} tree The owner tree
23200 * @param {Node} this This node
23201 * @param {Node} node The child node to be removed
23203 "beforeremove" : true,
23205 * @event beforemove
23206 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23207 * @param {Tree} tree The owner tree
23208 * @param {Node} this This node
23209 * @param {Node} oldParent The parent of this node
23210 * @param {Node} newParent The new parent this node is moving to
23211 * @param {Number} index The index it is being moved to
23213 "beforemove" : true,
23215 * @event beforeinsert
23216 * Fires before a new child is inserted, return false to cancel the insert.
23217 * @param {Tree} tree The owner tree
23218 * @param {Node} this This node
23219 * @param {Node} node The child node to be inserted
23220 * @param {Node} refNode The child node the node is being inserted before
23222 "beforeinsert" : true
23224 this.listeners = this.attributes.listeners;
23225 Roo.data.Node.superclass.constructor.call(this);
23228 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23229 fireEvent : function(evtName){
23230 // first do standard event for this node
23231 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23234 // then bubble it up to the tree if the event wasn't cancelled
23235 var ot = this.getOwnerTree();
23237 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23245 * Returns true if this node is a leaf
23246 * @return {Boolean}
23248 isLeaf : function(){
23249 return this.leaf === true;
23253 setFirstChild : function(node){
23254 this.firstChild = node;
23258 setLastChild : function(node){
23259 this.lastChild = node;
23264 * Returns true if this node is the last child of its parent
23265 * @return {Boolean}
23267 isLast : function(){
23268 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23272 * Returns true if this node is the first child of its parent
23273 * @return {Boolean}
23275 isFirst : function(){
23276 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23279 hasChildNodes : function(){
23280 return !this.isLeaf() && this.childNodes.length > 0;
23284 * Insert node(s) as the last child node of this node.
23285 * @param {Node/Array} node The node or Array of nodes to append
23286 * @return {Node} The appended node if single append, or null if an array was passed
23288 appendChild : function(node){
23290 if(node instanceof Array){
23292 }else if(arguments.length > 1){
23295 // if passed an array or multiple args do them one by one
23297 for(var i = 0, len = multi.length; i < len; i++) {
23298 this.appendChild(multi[i]);
23301 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23304 var index = this.childNodes.length;
23305 var oldParent = node.parentNode;
23306 // it's a move, make sure we move it cleanly
23308 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23311 oldParent.removeChild(node);
23313 index = this.childNodes.length;
23315 this.setFirstChild(node);
23317 this.childNodes.push(node);
23318 node.parentNode = this;
23319 var ps = this.childNodes[index-1];
23321 node.previousSibling = ps;
23322 ps.nextSibling = node;
23324 node.previousSibling = null;
23326 node.nextSibling = null;
23327 this.setLastChild(node);
23328 node.setOwnerTree(this.getOwnerTree());
23329 this.fireEvent("append", this.ownerTree, this, node, index);
23331 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23338 * Removes a child node from this node.
23339 * @param {Node} node The node to remove
23340 * @return {Node} The removed node
23342 removeChild : function(node){
23343 var index = this.childNodes.indexOf(node);
23347 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23351 // remove it from childNodes collection
23352 this.childNodes.splice(index, 1);
23355 if(node.previousSibling){
23356 node.previousSibling.nextSibling = node.nextSibling;
23358 if(node.nextSibling){
23359 node.nextSibling.previousSibling = node.previousSibling;
23362 // update child refs
23363 if(this.firstChild == node){
23364 this.setFirstChild(node.nextSibling);
23366 if(this.lastChild == node){
23367 this.setLastChild(node.previousSibling);
23370 node.setOwnerTree(null);
23371 // clear any references from the node
23372 node.parentNode = null;
23373 node.previousSibling = null;
23374 node.nextSibling = null;
23375 this.fireEvent("remove", this.ownerTree, this, node);
23380 * Inserts the first node before the second node in this nodes childNodes collection.
23381 * @param {Node} node The node to insert
23382 * @param {Node} refNode The node to insert before (if null the node is appended)
23383 * @return {Node} The inserted node
23385 insertBefore : function(node, refNode){
23386 if(!refNode){ // like standard Dom, refNode can be null for append
23387 return this.appendChild(node);
23390 if(node == refNode){
23394 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23397 var index = this.childNodes.indexOf(refNode);
23398 var oldParent = node.parentNode;
23399 var refIndex = index;
23401 // when moving internally, indexes will change after remove
23402 if(oldParent == this && this.childNodes.indexOf(node) < index){
23406 // it's a move, make sure we move it cleanly
23408 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23411 oldParent.removeChild(node);
23414 this.setFirstChild(node);
23416 this.childNodes.splice(refIndex, 0, node);
23417 node.parentNode = this;
23418 var ps = this.childNodes[refIndex-1];
23420 node.previousSibling = ps;
23421 ps.nextSibling = node;
23423 node.previousSibling = null;
23425 node.nextSibling = refNode;
23426 refNode.previousSibling = node;
23427 node.setOwnerTree(this.getOwnerTree());
23428 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23430 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23436 * Returns the child node at the specified index.
23437 * @param {Number} index
23440 item : function(index){
23441 return this.childNodes[index];
23445 * Replaces one child node in this node with another.
23446 * @param {Node} newChild The replacement node
23447 * @param {Node} oldChild The node to replace
23448 * @return {Node} The replaced node
23450 replaceChild : function(newChild, oldChild){
23451 this.insertBefore(newChild, oldChild);
23452 this.removeChild(oldChild);
23457 * Returns the index of a child node
23458 * @param {Node} node
23459 * @return {Number} The index of the node or -1 if it was not found
23461 indexOf : function(child){
23462 return this.childNodes.indexOf(child);
23466 * Returns the tree this node is in.
23469 getOwnerTree : function(){
23470 // if it doesn't have one, look for one
23471 if(!this.ownerTree){
23475 this.ownerTree = p.ownerTree;
23481 return this.ownerTree;
23485 * Returns depth of this node (the root node has a depth of 0)
23488 getDepth : function(){
23491 while(p.parentNode){
23499 setOwnerTree : function(tree){
23500 // if it's move, we need to update everyone
23501 if(tree != this.ownerTree){
23502 if(this.ownerTree){
23503 this.ownerTree.unregisterNode(this);
23505 this.ownerTree = tree;
23506 var cs = this.childNodes;
23507 for(var i = 0, len = cs.length; i < len; i++) {
23508 cs[i].setOwnerTree(tree);
23511 tree.registerNode(this);
23517 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23518 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23519 * @return {String} The path
23521 getPath : function(attr){
23522 attr = attr || "id";
23523 var p = this.parentNode;
23524 var b = [this.attributes[attr]];
23526 b.unshift(p.attributes[attr]);
23529 var sep = this.getOwnerTree().pathSeparator;
23530 return sep + b.join(sep);
23534 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23535 * function call will be the scope provided or the current node. The arguments to the function
23536 * will be the args provided or the current node. If the function returns false at any point,
23537 * the bubble is stopped.
23538 * @param {Function} fn The function to call
23539 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23540 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23542 bubble : function(fn, scope, args){
23545 if(fn.call(scope || p, args || p) === false){
23553 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23554 * function call will be the scope provided or the current node. The arguments to the function
23555 * will be the args provided or the current node. If the function returns false at any point,
23556 * the cascade is stopped on that branch.
23557 * @param {Function} fn The function to call
23558 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23559 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23561 cascade : function(fn, scope, args){
23562 if(fn.call(scope || this, args || this) !== false){
23563 var cs = this.childNodes;
23564 for(var i = 0, len = cs.length; i < len; i++) {
23565 cs[i].cascade(fn, scope, args);
23571 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23572 * function call will be the scope provided or the current node. The arguments to the function
23573 * will be the args provided or the current node. If the function returns false at any point,
23574 * the iteration stops.
23575 * @param {Function} fn The function to call
23576 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23577 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23579 eachChild : function(fn, scope, args){
23580 var cs = this.childNodes;
23581 for(var i = 0, len = cs.length; i < len; i++) {
23582 if(fn.call(scope || this, args || cs[i]) === false){
23589 * Finds the first child that has the attribute with the specified value.
23590 * @param {String} attribute The attribute name
23591 * @param {Mixed} value The value to search for
23592 * @return {Node} The found child or null if none was found
23594 findChild : function(attribute, value){
23595 var cs = this.childNodes;
23596 for(var i = 0, len = cs.length; i < len; i++) {
23597 if(cs[i].attributes[attribute] == value){
23605 * Finds the first child by a custom function. The child matches if the function passed
23607 * @param {Function} fn
23608 * @param {Object} scope (optional)
23609 * @return {Node} The found child or null if none was found
23611 findChildBy : function(fn, scope){
23612 var cs = this.childNodes;
23613 for(var i = 0, len = cs.length; i < len; i++) {
23614 if(fn.call(scope||cs[i], cs[i]) === true){
23622 * Sorts this nodes children using the supplied sort function
23623 * @param {Function} fn
23624 * @param {Object} scope (optional)
23626 sort : function(fn, scope){
23627 var cs = this.childNodes;
23628 var len = cs.length;
23630 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23632 for(var i = 0; i < len; i++){
23634 n.previousSibling = cs[i-1];
23635 n.nextSibling = cs[i+1];
23637 this.setFirstChild(n);
23640 this.setLastChild(n);
23647 * Returns true if this node is an ancestor (at any point) of the passed node.
23648 * @param {Node} node
23649 * @return {Boolean}
23651 contains : function(node){
23652 return node.isAncestor(this);
23656 * Returns true if the passed node is an ancestor (at any point) of this node.
23657 * @param {Node} node
23658 * @return {Boolean}
23660 isAncestor : function(node){
23661 var p = this.parentNode;
23671 toString : function(){
23672 return "[Node"+(this.id?" "+this.id:"")+"]";
23676 * Ext JS Library 1.1.1
23677 * Copyright(c) 2006-2007, Ext JS, LLC.
23679 * Originally Released Under LGPL - original licence link has changed is not relivant.
23682 * <script type="text/javascript">
23687 * @extends Roo.Element
23688 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23689 * automatic maintaining of shadow/shim positions.
23690 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23691 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23692 * you can pass a string with a CSS class name. False turns off the shadow.
23693 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23694 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23695 * @cfg {String} cls CSS class to add to the element
23696 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23697 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23699 * @param {Object} config An object with config options.
23700 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23703 Roo.Layer = function(config, existingEl){
23704 config = config || {};
23705 var dh = Roo.DomHelper;
23706 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23708 this.dom = Roo.getDom(existingEl);
23711 var o = config.dh || {tag: "div", cls: "x-layer"};
23712 this.dom = dh.append(pel, o);
23715 this.addClass(config.cls);
23717 this.constrain = config.constrain !== false;
23718 this.visibilityMode = Roo.Element.VISIBILITY;
23720 this.id = this.dom.id = config.id;
23722 this.id = Roo.id(this.dom);
23724 this.zindex = config.zindex || this.getZIndex();
23725 this.position("absolute", this.zindex);
23727 this.shadowOffset = config.shadowOffset || 4;
23728 this.shadow = new Roo.Shadow({
23729 offset : this.shadowOffset,
23730 mode : config.shadow
23733 this.shadowOffset = 0;
23735 this.useShim = config.shim !== false && Roo.useShims;
23736 this.useDisplay = config.useDisplay;
23740 var supr = Roo.Element.prototype;
23742 // shims are shared among layer to keep from having 100 iframes
23745 Roo.extend(Roo.Layer, Roo.Element, {
23747 getZIndex : function(){
23748 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23751 getShim : function(){
23758 var shim = shims.shift();
23760 shim = this.createShim();
23761 shim.enableDisplayMode('block');
23762 shim.dom.style.display = 'none';
23763 shim.dom.style.visibility = 'visible';
23765 var pn = this.dom.parentNode;
23766 if(shim.dom.parentNode != pn){
23767 pn.insertBefore(shim.dom, this.dom);
23769 shim.setStyle('z-index', this.getZIndex()-2);
23774 hideShim : function(){
23776 this.shim.setDisplayed(false);
23777 shims.push(this.shim);
23782 disableShadow : function(){
23784 this.shadowDisabled = true;
23785 this.shadow.hide();
23786 this.lastShadowOffset = this.shadowOffset;
23787 this.shadowOffset = 0;
23791 enableShadow : function(show){
23793 this.shadowDisabled = false;
23794 this.shadowOffset = this.lastShadowOffset;
23795 delete this.lastShadowOffset;
23803 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23804 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23805 sync : function(doShow){
23806 var sw = this.shadow;
23807 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23808 var sh = this.getShim();
23810 var w = this.getWidth(),
23811 h = this.getHeight();
23813 var l = this.getLeft(true),
23814 t = this.getTop(true);
23816 if(sw && !this.shadowDisabled){
23817 if(doShow && !sw.isVisible()){
23820 sw.realign(l, t, w, h);
23826 // fit the shim behind the shadow, so it is shimmed too
23827 var a = sw.adjusts, s = sh.dom.style;
23828 s.left = (Math.min(l, l+a.l))+"px";
23829 s.top = (Math.min(t, t+a.t))+"px";
23830 s.width = (w+a.w)+"px";
23831 s.height = (h+a.h)+"px";
23838 sh.setLeftTop(l, t);
23845 destroy : function(){
23848 this.shadow.hide();
23850 this.removeAllListeners();
23851 var pn = this.dom.parentNode;
23853 pn.removeChild(this.dom);
23855 Roo.Element.uncache(this.id);
23858 remove : function(){
23863 beginUpdate : function(){
23864 this.updating = true;
23868 endUpdate : function(){
23869 this.updating = false;
23874 hideUnders : function(negOffset){
23876 this.shadow.hide();
23882 constrainXY : function(){
23883 if(this.constrain){
23884 var vw = Roo.lib.Dom.getViewWidth(),
23885 vh = Roo.lib.Dom.getViewHeight();
23886 var s = Roo.get(document).getScroll();
23888 var xy = this.getXY();
23889 var x = xy[0], y = xy[1];
23890 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23891 // only move it if it needs it
23893 // first validate right/bottom
23894 if((x + w) > vw+s.left){
23895 x = vw - w - this.shadowOffset;
23898 if((y + h) > vh+s.top){
23899 y = vh - h - this.shadowOffset;
23902 // then make sure top/left isn't negative
23913 var ay = this.avoidY;
23914 if(y <= ay && (y+h) >= ay){
23920 supr.setXY.call(this, xy);
23926 isVisible : function(){
23927 return this.visible;
23931 showAction : function(){
23932 this.visible = true; // track visibility to prevent getStyle calls
23933 if(this.useDisplay === true){
23934 this.setDisplayed("");
23935 }else if(this.lastXY){
23936 supr.setXY.call(this, this.lastXY);
23937 }else if(this.lastLT){
23938 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23943 hideAction : function(){
23944 this.visible = false;
23945 if(this.useDisplay === true){
23946 this.setDisplayed(false);
23948 this.setLeftTop(-10000,-10000);
23952 // overridden Element method
23953 setVisible : function(v, a, d, c, e){
23958 var cb = function(){
23963 }.createDelegate(this);
23964 supr.setVisible.call(this, true, true, d, cb, e);
23967 this.hideUnders(true);
23976 }.createDelegate(this);
23978 supr.setVisible.call(this, v, a, d, cb, e);
23987 storeXY : function(xy){
23988 delete this.lastLT;
23992 storeLeftTop : function(left, top){
23993 delete this.lastXY;
23994 this.lastLT = [left, top];
23998 beforeFx : function(){
23999 this.beforeAction();
24000 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
24004 afterFx : function(){
24005 Roo.Layer.superclass.afterFx.apply(this, arguments);
24006 this.sync(this.isVisible());
24010 beforeAction : function(){
24011 if(!this.updating && this.shadow){
24012 this.shadow.hide();
24016 // overridden Element method
24017 setLeft : function(left){
24018 this.storeLeftTop(left, this.getTop(true));
24019 supr.setLeft.apply(this, arguments);
24023 setTop : function(top){
24024 this.storeLeftTop(this.getLeft(true), top);
24025 supr.setTop.apply(this, arguments);
24029 setLeftTop : function(left, top){
24030 this.storeLeftTop(left, top);
24031 supr.setLeftTop.apply(this, arguments);
24035 setXY : function(xy, a, d, c, e){
24037 this.beforeAction();
24039 var cb = this.createCB(c);
24040 supr.setXY.call(this, xy, a, d, cb, e);
24047 createCB : function(c){
24058 // overridden Element method
24059 setX : function(x, a, d, c, e){
24060 this.setXY([x, this.getY()], a, d, c, e);
24063 // overridden Element method
24064 setY : function(y, a, d, c, e){
24065 this.setXY([this.getX(), y], a, d, c, e);
24068 // overridden Element method
24069 setSize : function(w, h, a, d, c, e){
24070 this.beforeAction();
24071 var cb = this.createCB(c);
24072 supr.setSize.call(this, w, h, a, d, cb, e);
24078 // overridden Element method
24079 setWidth : function(w, a, d, c, e){
24080 this.beforeAction();
24081 var cb = this.createCB(c);
24082 supr.setWidth.call(this, w, a, d, cb, e);
24088 // overridden Element method
24089 setHeight : function(h, a, d, c, e){
24090 this.beforeAction();
24091 var cb = this.createCB(c);
24092 supr.setHeight.call(this, h, a, d, cb, e);
24098 // overridden Element method
24099 setBounds : function(x, y, w, h, a, d, c, e){
24100 this.beforeAction();
24101 var cb = this.createCB(c);
24103 this.storeXY([x, y]);
24104 supr.setXY.call(this, [x, y]);
24105 supr.setSize.call(this, w, h, a, d, cb, e);
24108 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24114 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24115 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24116 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24117 * @param {Number} zindex The new z-index to set
24118 * @return {this} The Layer
24120 setZIndex : function(zindex){
24121 this.zindex = zindex;
24122 this.setStyle("z-index", zindex + 2);
24124 this.shadow.setZIndex(zindex + 1);
24127 this.shim.setStyle("z-index", zindex);
24133 * Ext JS Library 1.1.1
24134 * Copyright(c) 2006-2007, Ext JS, LLC.
24136 * Originally Released Under LGPL - original licence link has changed is not relivant.
24139 * <script type="text/javascript">
24144 * @class Roo.Shadow
24145 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24146 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24147 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24149 * Create a new Shadow
24150 * @param {Object} config The config object
24152 Roo.Shadow = function(config){
24153 Roo.apply(this, config);
24154 if(typeof this.mode != "string"){
24155 this.mode = this.defaultMode;
24157 var o = this.offset, a = {h: 0};
24158 var rad = Math.floor(this.offset/2);
24159 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24165 a.l -= this.offset + rad;
24166 a.t -= this.offset + rad;
24177 a.l -= (this.offset - rad);
24178 a.t -= this.offset + rad;
24180 a.w -= (this.offset - rad)*2;
24191 a.l -= (this.offset - rad);
24192 a.t -= (this.offset - rad);
24194 a.w -= (this.offset + rad + 1);
24195 a.h -= (this.offset + rad);
24204 Roo.Shadow.prototype = {
24206 * @cfg {String} mode
24207 * The shadow display mode. Supports the following options:<br />
24208 * sides: Shadow displays on both sides and bottom only<br />
24209 * frame: Shadow displays equally on all four sides<br />
24210 * drop: Traditional bottom-right drop shadow (default)
24213 * @cfg {String} offset
24214 * The number of pixels to offset the shadow from the element (defaults to 4)
24219 defaultMode: "drop",
24222 * Displays the shadow under the target element
24223 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24225 show : function(target){
24226 target = Roo.get(target);
24228 this.el = Roo.Shadow.Pool.pull();
24229 if(this.el.dom.nextSibling != target.dom){
24230 this.el.insertBefore(target);
24233 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24235 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24238 target.getLeft(true),
24239 target.getTop(true),
24243 this.el.dom.style.display = "block";
24247 * Returns true if the shadow is visible, else false
24249 isVisible : function(){
24250 return this.el ? true : false;
24254 * Direct alignment when values are already available. Show must be called at least once before
24255 * calling this method to ensure it is initialized.
24256 * @param {Number} left The target element left position
24257 * @param {Number} top The target element top position
24258 * @param {Number} width The target element width
24259 * @param {Number} height The target element height
24261 realign : function(l, t, w, h){
24265 var a = this.adjusts, d = this.el.dom, s = d.style;
24267 s.left = (l+a.l)+"px";
24268 s.top = (t+a.t)+"px";
24269 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24271 if(s.width != sws || s.height != shs){
24275 var cn = d.childNodes;
24276 var sww = Math.max(0, (sw-12))+"px";
24277 cn[0].childNodes[1].style.width = sww;
24278 cn[1].childNodes[1].style.width = sww;
24279 cn[2].childNodes[1].style.width = sww;
24280 cn[1].style.height = Math.max(0, (sh-12))+"px";
24286 * Hides this shadow
24290 this.el.dom.style.display = "none";
24291 Roo.Shadow.Pool.push(this.el);
24297 * Adjust the z-index of this shadow
24298 * @param {Number} zindex The new z-index
24300 setZIndex : function(z){
24303 this.el.setStyle("z-index", z);
24308 // Private utility class that manages the internal Shadow cache
24309 Roo.Shadow.Pool = function(){
24311 var markup = Roo.isIE ?
24312 '<div class="x-ie-shadow"></div>' :
24313 '<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>';
24316 var sh = p.shift();
24318 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24319 sh.autoBoxAdjust = false;
24324 push : function(sh){
24330 * Ext JS Library 1.1.1
24331 * Copyright(c) 2006-2007, Ext JS, LLC.
24333 * Originally Released Under LGPL - original licence link has changed is not relivant.
24336 * <script type="text/javascript">
24341 * @class Roo.SplitBar
24342 * @extends Roo.util.Observable
24343 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24347 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24348 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24349 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24350 split.minSize = 100;
24351 split.maxSize = 600;
24352 split.animate = true;
24353 split.on('moved', splitterMoved);
24356 * Create a new SplitBar
24357 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24358 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24359 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24360 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24361 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24362 position of the SplitBar).
24364 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24367 this.el = Roo.get(dragElement, true);
24368 this.el.dom.unselectable = "on";
24370 this.resizingEl = Roo.get(resizingElement, true);
24374 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24375 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24378 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24381 * The minimum size of the resizing element. (Defaults to 0)
24387 * The maximum size of the resizing element. (Defaults to 2000)
24390 this.maxSize = 2000;
24393 * Whether to animate the transition to the new size
24396 this.animate = false;
24399 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24402 this.useShim = false;
24407 if(!existingProxy){
24409 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24411 this.proxy = Roo.get(existingProxy).dom;
24414 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24417 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24420 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24423 this.dragSpecs = {};
24426 * @private The adapter to use to positon and resize elements
24428 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24429 this.adapter.init(this);
24431 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24433 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24434 this.el.addClass("x-splitbar-h");
24437 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24438 this.el.addClass("x-splitbar-v");
24444 * Fires when the splitter is moved (alias for {@link #event-moved})
24445 * @param {Roo.SplitBar} this
24446 * @param {Number} newSize the new width or height
24451 * Fires when the splitter is moved
24452 * @param {Roo.SplitBar} this
24453 * @param {Number} newSize the new width or height
24457 * @event beforeresize
24458 * Fires before the splitter is dragged
24459 * @param {Roo.SplitBar} this
24461 "beforeresize" : true,
24463 "beforeapply" : true
24466 Roo.util.Observable.call(this);
24469 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24470 onStartProxyDrag : function(x, y){
24471 this.fireEvent("beforeresize", this);
24473 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24475 o.enableDisplayMode("block");
24476 // all splitbars share the same overlay
24477 Roo.SplitBar.prototype.overlay = o;
24479 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24480 this.overlay.show();
24481 Roo.get(this.proxy).setDisplayed("block");
24482 var size = this.adapter.getElementSize(this);
24483 this.activeMinSize = this.getMinimumSize();;
24484 this.activeMaxSize = this.getMaximumSize();;
24485 var c1 = size - this.activeMinSize;
24486 var c2 = Math.max(this.activeMaxSize - size, 0);
24487 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24488 this.dd.resetConstraints();
24489 this.dd.setXConstraint(
24490 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24491 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24493 this.dd.setYConstraint(0, 0);
24495 this.dd.resetConstraints();
24496 this.dd.setXConstraint(0, 0);
24497 this.dd.setYConstraint(
24498 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24499 this.placement == Roo.SplitBar.TOP ? c2 : c1
24502 this.dragSpecs.startSize = size;
24503 this.dragSpecs.startPoint = [x, y];
24504 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24508 * @private Called after the drag operation by the DDProxy
24510 onEndProxyDrag : function(e){
24511 Roo.get(this.proxy).setDisplayed(false);
24512 var endPoint = Roo.lib.Event.getXY(e);
24514 this.overlay.hide();
24517 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24518 newSize = this.dragSpecs.startSize +
24519 (this.placement == Roo.SplitBar.LEFT ?
24520 endPoint[0] - this.dragSpecs.startPoint[0] :
24521 this.dragSpecs.startPoint[0] - endPoint[0]
24524 newSize = this.dragSpecs.startSize +
24525 (this.placement == Roo.SplitBar.TOP ?
24526 endPoint[1] - this.dragSpecs.startPoint[1] :
24527 this.dragSpecs.startPoint[1] - endPoint[1]
24530 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24531 if(newSize != this.dragSpecs.startSize){
24532 if(this.fireEvent('beforeapply', this, newSize) !== false){
24533 this.adapter.setElementSize(this, newSize);
24534 this.fireEvent("moved", this, newSize);
24535 this.fireEvent("resize", this, newSize);
24541 * Get the adapter this SplitBar uses
24542 * @return The adapter object
24544 getAdapter : function(){
24545 return this.adapter;
24549 * Set the adapter this SplitBar uses
24550 * @param {Object} adapter A SplitBar adapter object
24552 setAdapter : function(adapter){
24553 this.adapter = adapter;
24554 this.adapter.init(this);
24558 * Gets the minimum size for the resizing element
24559 * @return {Number} The minimum size
24561 getMinimumSize : function(){
24562 return this.minSize;
24566 * Sets the minimum size for the resizing element
24567 * @param {Number} minSize The minimum size
24569 setMinimumSize : function(minSize){
24570 this.minSize = minSize;
24574 * Gets the maximum size for the resizing element
24575 * @return {Number} The maximum size
24577 getMaximumSize : function(){
24578 return this.maxSize;
24582 * Sets the maximum size for the resizing element
24583 * @param {Number} maxSize The maximum size
24585 setMaximumSize : function(maxSize){
24586 this.maxSize = maxSize;
24590 * Sets the initialize size for the resizing element
24591 * @param {Number} size The initial size
24593 setCurrentSize : function(size){
24594 var oldAnimate = this.animate;
24595 this.animate = false;
24596 this.adapter.setElementSize(this, size);
24597 this.animate = oldAnimate;
24601 * Destroy this splitbar.
24602 * @param {Boolean} removeEl True to remove the element
24604 destroy : function(removeEl){
24606 this.shim.remove();
24609 this.proxy.parentNode.removeChild(this.proxy);
24617 * @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.
24619 Roo.SplitBar.createProxy = function(dir){
24620 var proxy = new Roo.Element(document.createElement("div"));
24621 proxy.unselectable();
24622 var cls = 'x-splitbar-proxy';
24623 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24624 document.body.appendChild(proxy.dom);
24629 * @class Roo.SplitBar.BasicLayoutAdapter
24630 * Default Adapter. It assumes the splitter and resizing element are not positioned
24631 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24633 Roo.SplitBar.BasicLayoutAdapter = function(){
24636 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24637 // do nothing for now
24638 init : function(s){
24642 * Called before drag operations to get the current size of the resizing element.
24643 * @param {Roo.SplitBar} s The SplitBar using this adapter
24645 getElementSize : function(s){
24646 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24647 return s.resizingEl.getWidth();
24649 return s.resizingEl.getHeight();
24654 * Called after drag operations to set the size of the resizing element.
24655 * @param {Roo.SplitBar} s The SplitBar using this adapter
24656 * @param {Number} newSize The new size to set
24657 * @param {Function} onComplete A function to be invoked when resizing is complete
24659 setElementSize : function(s, newSize, onComplete){
24660 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24662 s.resizingEl.setWidth(newSize);
24664 onComplete(s, newSize);
24667 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24672 s.resizingEl.setHeight(newSize);
24674 onComplete(s, newSize);
24677 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24684 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24685 * @extends Roo.SplitBar.BasicLayoutAdapter
24686 * Adapter that moves the splitter element to align with the resized sizing element.
24687 * Used with an absolute positioned SplitBar.
24688 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24689 * document.body, make sure you assign an id to the body element.
24691 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24692 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24693 this.container = Roo.get(container);
24696 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24697 init : function(s){
24698 this.basic.init(s);
24701 getElementSize : function(s){
24702 return this.basic.getElementSize(s);
24705 setElementSize : function(s, newSize, onComplete){
24706 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24709 moveSplitter : function(s){
24710 var yes = Roo.SplitBar;
24711 switch(s.placement){
24713 s.el.setX(s.resizingEl.getRight());
24716 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24719 s.el.setY(s.resizingEl.getBottom());
24722 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24729 * Orientation constant - Create a vertical SplitBar
24733 Roo.SplitBar.VERTICAL = 1;
24736 * Orientation constant - Create a horizontal SplitBar
24740 Roo.SplitBar.HORIZONTAL = 2;
24743 * Placement constant - The resizing element is to the left of the splitter element
24747 Roo.SplitBar.LEFT = 1;
24750 * Placement constant - The resizing element is to the right of the splitter element
24754 Roo.SplitBar.RIGHT = 2;
24757 * Placement constant - The resizing element is positioned above the splitter element
24761 Roo.SplitBar.TOP = 3;
24764 * Placement constant - The resizing element is positioned under splitter element
24768 Roo.SplitBar.BOTTOM = 4;
24771 * Ext JS Library 1.1.1
24772 * Copyright(c) 2006-2007, Ext JS, LLC.
24774 * Originally Released Under LGPL - original licence link has changed is not relivant.
24777 * <script type="text/javascript">
24782 * @extends Roo.util.Observable
24783 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24784 * This class also supports single and multi selection modes. <br>
24785 * Create a data model bound view:
24787 var store = new Roo.data.Store(...);
24789 var view = new Roo.View({
24791 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24793 singleSelect: true,
24794 selectedClass: "ydataview-selected",
24798 // listen for node click?
24799 view.on("click", function(vw, index, node, e){
24800 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24804 dataModel.load("foobar.xml");
24806 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24808 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24809 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24811 * Note: old style constructor is still suported (container, template, config)
24814 * Create a new View
24815 * @param {Object} config The config object
24818 Roo.View = function(config, depreciated_tpl, depreciated_config){
24820 if (typeof(depreciated_tpl) == 'undefined') {
24821 // new way.. - universal constructor.
24822 Roo.apply(this, config);
24823 this.el = Roo.get(this.el);
24826 this.el = Roo.get(config);
24827 this.tpl = depreciated_tpl;
24828 Roo.apply(this, depreciated_config);
24830 this.wrapEl = this.el.wrap().wrap();
24831 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24834 if(typeof(this.tpl) == "string"){
24835 this.tpl = new Roo.Template(this.tpl);
24837 // support xtype ctors..
24838 this.tpl = new Roo.factory(this.tpl, Roo);
24842 this.tpl.compile();
24850 * @event beforeclick
24851 * Fires before a click is processed. Returns false to cancel the default action.
24852 * @param {Roo.View} this
24853 * @param {Number} index The index of the target node
24854 * @param {HTMLElement} node The target node
24855 * @param {Roo.EventObject} e The raw event object
24857 "beforeclick" : true,
24860 * Fires when a template node is clicked.
24861 * @param {Roo.View} this
24862 * @param {Number} index The index of the target node
24863 * @param {HTMLElement} node The target node
24864 * @param {Roo.EventObject} e The raw event object
24869 * Fires when a template node is double clicked.
24870 * @param {Roo.View} this
24871 * @param {Number} index The index of the target node
24872 * @param {HTMLElement} node The target node
24873 * @param {Roo.EventObject} e The raw event object
24877 * @event contextmenu
24878 * Fires when a template node is right clicked.
24879 * @param {Roo.View} this
24880 * @param {Number} index The index of the target node
24881 * @param {HTMLElement} node The target node
24882 * @param {Roo.EventObject} e The raw event object
24884 "contextmenu" : true,
24886 * @event selectionchange
24887 * Fires when the selected nodes change.
24888 * @param {Roo.View} this
24889 * @param {Array} selections Array of the selected nodes
24891 "selectionchange" : true,
24894 * @event beforeselect
24895 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24896 * @param {Roo.View} this
24897 * @param {HTMLElement} node The node to be selected
24898 * @param {Array} selections Array of currently selected nodes
24900 "beforeselect" : true,
24902 * @event preparedata
24903 * Fires on every row to render, to allow you to change the data.
24904 * @param {Roo.View} this
24905 * @param {Object} data to be rendered (change this)
24907 "preparedata" : true
24915 "click": this.onClick,
24916 "dblclick": this.onDblClick,
24917 "contextmenu": this.onContextMenu,
24921 this.selections = [];
24923 this.cmp = new Roo.CompositeElementLite([]);
24925 this.store = Roo.factory(this.store, Roo.data);
24926 this.setStore(this.store, true);
24929 if ( this.footer && this.footer.xtype) {
24931 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24933 this.footer.dataSource = this.store
24934 this.footer.container = fctr;
24935 this.footer = Roo.factory(this.footer, Roo);
24936 fctr.insertFirst(this.el);
24938 // this is a bit insane - as the paging toolbar seems to detach the el..
24939 // dom.parentNode.parentNode.parentNode
24940 // they get detached?
24944 Roo.View.superclass.constructor.call(this);
24949 Roo.extend(Roo.View, Roo.util.Observable, {
24952 * @cfg {Roo.data.Store} store Data store to load data from.
24957 * @cfg {String|Roo.Element} el The container element.
24962 * @cfg {String|Roo.Template} tpl The template used by this View
24966 * @cfg {String} dataName the named area of the template to use as the data area
24967 * Works with domtemplates roo-name="name"
24971 * @cfg {String} selectedClass The css class to add to selected nodes
24973 selectedClass : "x-view-selected",
24975 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24980 * @cfg {String} text to display on mask (default Loading)
24984 * @cfg {Boolean} multiSelect Allow multiple selection
24986 multiSelect : false,
24988 * @cfg {Boolean} singleSelect Allow single selection
24990 singleSelect: false,
24993 * @cfg {Boolean} toggleSelect - selecting
24995 toggleSelect : false,
24998 * Returns the element this view is bound to.
24999 * @return {Roo.Element}
25001 getEl : function(){
25002 return this.wrapEl;
25008 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25010 refresh : function(){
25011 Roo.log('refresh');
25014 // if we are using something like 'domtemplate', then
25015 // the what gets used is:
25016 // t.applySubtemplate(NAME, data, wrapping data..)
25017 // the outer template then get' applied with
25018 // the store 'extra data'
25019 // and the body get's added to the
25020 // roo-name="data" node?
25021 // <span class='roo-tpl-{name}'></span> ?????
25025 this.clearSelections();
25026 this.el.update("");
25028 var records = this.store.getRange();
25029 if(records.length < 1) {
25031 // is this valid?? = should it render a template??
25033 this.el.update(this.emptyText);
25037 if (this.dataName) {
25038 this.el.update(t.apply(this.store.meta)); //????
25039 el = this.el.child('.roo-tpl-' + this.dataName);
25042 for(var i = 0, len = records.length; i < len; i++){
25043 var data = this.prepareData(records[i].data, i, records[i]);
25044 this.fireEvent("preparedata", this, data, i, records[i]);
25045 html[html.length] = Roo.util.Format.trim(
25047 t.applySubtemplate(this.dataName, data, this.store.meta) :
25054 el.update(html.join(""));
25055 this.nodes = el.dom.childNodes;
25056 this.updateIndexes(0);
25061 * Function to override to reformat the data that is sent to
25062 * the template for each node.
25063 * DEPRICATED - use the preparedata event handler.
25064 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25065 * a JSON object for an UpdateManager bound view).
25067 prepareData : function(data, index, record)
25069 this.fireEvent("preparedata", this, data, index, record);
25073 onUpdate : function(ds, record){
25074 Roo.log('on update');
25075 this.clearSelections();
25076 var index = this.store.indexOf(record);
25077 var n = this.nodes[index];
25078 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25079 n.parentNode.removeChild(n);
25080 this.updateIndexes(index, index);
25086 onAdd : function(ds, records, index)
25088 Roo.log(['on Add', ds, records, index] );
25089 this.clearSelections();
25090 if(this.nodes.length == 0){
25094 var n = this.nodes[index];
25095 for(var i = 0, len = records.length; i < len; i++){
25096 var d = this.prepareData(records[i].data, i, records[i]);
25098 this.tpl.insertBefore(n, d);
25101 this.tpl.append(this.el, d);
25104 this.updateIndexes(index);
25107 onRemove : function(ds, record, index){
25108 Roo.log('onRemove');
25109 this.clearSelections();
25110 var el = this.dataName ?
25111 this.el.child('.roo-tpl-' + this.dataName) :
25114 el.dom.removeChild(this.nodes[index]);
25115 this.updateIndexes(index);
25119 * Refresh an individual node.
25120 * @param {Number} index
25122 refreshNode : function(index){
25123 this.onUpdate(this.store, this.store.getAt(index));
25126 updateIndexes : function(startIndex, endIndex){
25127 var ns = this.nodes;
25128 startIndex = startIndex || 0;
25129 endIndex = endIndex || ns.length - 1;
25130 for(var i = startIndex; i <= endIndex; i++){
25131 ns[i].nodeIndex = i;
25136 * Changes the data store this view uses and refresh the view.
25137 * @param {Store} store
25139 setStore : function(store, initial){
25140 if(!initial && this.store){
25141 this.store.un("datachanged", this.refresh);
25142 this.store.un("add", this.onAdd);
25143 this.store.un("remove", this.onRemove);
25144 this.store.un("update", this.onUpdate);
25145 this.store.un("clear", this.refresh);
25146 this.store.un("beforeload", this.onBeforeLoad);
25147 this.store.un("load", this.onLoad);
25148 this.store.un("loadexception", this.onLoad);
25152 store.on("datachanged", this.refresh, this);
25153 store.on("add", this.onAdd, this);
25154 store.on("remove", this.onRemove, this);
25155 store.on("update", this.onUpdate, this);
25156 store.on("clear", this.refresh, this);
25157 store.on("beforeload", this.onBeforeLoad, this);
25158 store.on("load", this.onLoad, this);
25159 store.on("loadexception", this.onLoad, this);
25167 * onbeforeLoad - masks the loading area.
25170 onBeforeLoad : function(store,opts)
25172 Roo.log('onBeforeLoad');
25174 this.el.update("");
25176 this.el.mask(this.mask ? this.mask : "Loading" );
25178 onLoad : function ()
25185 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25186 * @param {HTMLElement} node
25187 * @return {HTMLElement} The template node
25189 findItemFromChild : function(node){
25190 var el = this.dataName ?
25191 this.el.child('.roo-tpl-' + this.dataName,true) :
25194 if(!node || node.parentNode == el){
25197 var p = node.parentNode;
25198 while(p && p != el){
25199 if(p.parentNode == el){
25208 onClick : function(e){
25209 var item = this.findItemFromChild(e.getTarget());
25211 var index = this.indexOf(item);
25212 if(this.onItemClick(item, index, e) !== false){
25213 this.fireEvent("click", this, index, item, e);
25216 this.clearSelections();
25221 onContextMenu : function(e){
25222 var item = this.findItemFromChild(e.getTarget());
25224 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25229 onDblClick : function(e){
25230 var item = this.findItemFromChild(e.getTarget());
25232 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25236 onItemClick : function(item, index, e)
25238 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25241 if (this.toggleSelect) {
25242 var m = this.isSelected(item) ? 'unselect' : 'select';
25245 _t[m](item, true, false);
25248 if(this.multiSelect || this.singleSelect){
25249 if(this.multiSelect && e.shiftKey && this.lastSelection){
25250 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25252 this.select(item, this.multiSelect && e.ctrlKey);
25253 this.lastSelection = item;
25255 e.preventDefault();
25261 * Get the number of selected nodes.
25264 getSelectionCount : function(){
25265 return this.selections.length;
25269 * Get the currently selected nodes.
25270 * @return {Array} An array of HTMLElements
25272 getSelectedNodes : function(){
25273 return this.selections;
25277 * Get the indexes of the selected nodes.
25280 getSelectedIndexes : function(){
25281 var indexes = [], s = this.selections;
25282 for(var i = 0, len = s.length; i < len; i++){
25283 indexes.push(s[i].nodeIndex);
25289 * Clear all selections
25290 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25292 clearSelections : function(suppressEvent){
25293 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25294 this.cmp.elements = this.selections;
25295 this.cmp.removeClass(this.selectedClass);
25296 this.selections = [];
25297 if(!suppressEvent){
25298 this.fireEvent("selectionchange", this, this.selections);
25304 * Returns true if the passed node is selected
25305 * @param {HTMLElement/Number} node The node or node index
25306 * @return {Boolean}
25308 isSelected : function(node){
25309 var s = this.selections;
25313 node = this.getNode(node);
25314 return s.indexOf(node) !== -1;
25319 * @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
25320 * @param {Boolean} keepExisting (optional) true to keep existing selections
25321 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25323 select : function(nodeInfo, keepExisting, suppressEvent){
25324 if(nodeInfo instanceof Array){
25326 this.clearSelections(true);
25328 for(var i = 0, len = nodeInfo.length; i < len; i++){
25329 this.select(nodeInfo[i], true, true);
25333 var node = this.getNode(nodeInfo);
25334 if(!node || this.isSelected(node)){
25335 return; // already selected.
25338 this.clearSelections(true);
25340 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25341 Roo.fly(node).addClass(this.selectedClass);
25342 this.selections.push(node);
25343 if(!suppressEvent){
25344 this.fireEvent("selectionchange", this, this.selections);
25352 * @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
25353 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25354 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25356 unselect : function(nodeInfo, keepExisting, suppressEvent)
25358 if(nodeInfo instanceof Array){
25359 Roo.each(this.selections, function(s) {
25360 this.unselect(s, nodeInfo);
25364 var node = this.getNode(nodeInfo);
25365 if(!node || !this.isSelected(node)){
25366 Roo.log("not selected");
25367 return; // not selected.
25371 Roo.each(this.selections, function(s) {
25373 Roo.fly(node).removeClass(this.selectedClass);
25380 this.selections= ns;
25381 this.fireEvent("selectionchange", this, this.selections);
25385 * Gets a template node.
25386 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25387 * @return {HTMLElement} The node or null if it wasn't found
25389 getNode : function(nodeInfo){
25390 if(typeof nodeInfo == "string"){
25391 return document.getElementById(nodeInfo);
25392 }else if(typeof nodeInfo == "number"){
25393 return this.nodes[nodeInfo];
25399 * Gets a range template nodes.
25400 * @param {Number} startIndex
25401 * @param {Number} endIndex
25402 * @return {Array} An array of nodes
25404 getNodes : function(start, end){
25405 var ns = this.nodes;
25406 start = start || 0;
25407 end = typeof end == "undefined" ? ns.length - 1 : end;
25410 for(var i = start; i <= end; i++){
25414 for(var i = start; i >= end; i--){
25422 * Finds the index of the passed node
25423 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25424 * @return {Number} The index of the node or -1
25426 indexOf : function(node){
25427 node = this.getNode(node);
25428 if(typeof node.nodeIndex == "number"){
25429 return node.nodeIndex;
25431 var ns = this.nodes;
25432 for(var i = 0, len = ns.length; i < len; i++){
25442 * Ext JS Library 1.1.1
25443 * Copyright(c) 2006-2007, Ext JS, LLC.
25445 * Originally Released Under LGPL - original licence link has changed is not relivant.
25448 * <script type="text/javascript">
25452 * @class Roo.JsonView
25453 * @extends Roo.View
25454 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25456 var view = new Roo.JsonView({
25457 container: "my-element",
25458 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25463 // listen for node click?
25464 view.on("click", function(vw, index, node, e){
25465 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25468 // direct load of JSON data
25469 view.load("foobar.php");
25471 // Example from my blog list
25472 var tpl = new Roo.Template(
25473 '<div class="entry">' +
25474 '<a class="entry-title" href="{link}">{title}</a>' +
25475 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25476 "</div><hr />"
25479 var moreView = new Roo.JsonView({
25480 container : "entry-list",
25484 moreView.on("beforerender", this.sortEntries, this);
25486 url: "/blog/get-posts.php",
25487 params: "allposts=true",
25488 text: "Loading Blog Entries..."
25492 * Note: old code is supported with arguments : (container, template, config)
25496 * Create a new JsonView
25498 * @param {Object} config The config object
25501 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25504 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25506 var um = this.el.getUpdateManager();
25507 um.setRenderer(this);
25508 um.on("update", this.onLoad, this);
25509 um.on("failure", this.onLoadException, this);
25512 * @event beforerender
25513 * Fires before rendering of the downloaded JSON data.
25514 * @param {Roo.JsonView} this
25515 * @param {Object} data The JSON data loaded
25519 * Fires when data is loaded.
25520 * @param {Roo.JsonView} this
25521 * @param {Object} data The JSON data loaded
25522 * @param {Object} response The raw Connect response object
25525 * @event loadexception
25526 * Fires when loading fails.
25527 * @param {Roo.JsonView} this
25528 * @param {Object} response The raw Connect response object
25531 'beforerender' : true,
25533 'loadexception' : true
25536 Roo.extend(Roo.JsonView, Roo.View, {
25538 * @type {String} The root property in the loaded JSON object that contains the data
25543 * Refreshes the view.
25545 refresh : function(){
25546 this.clearSelections();
25547 this.el.update("");
25549 var o = this.jsonData;
25550 if(o && o.length > 0){
25551 for(var i = 0, len = o.length; i < len; i++){
25552 var data = this.prepareData(o[i], i, o);
25553 html[html.length] = this.tpl.apply(data);
25556 html.push(this.emptyText);
25558 this.el.update(html.join(""));
25559 this.nodes = this.el.dom.childNodes;
25560 this.updateIndexes(0);
25564 * 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.
25565 * @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:
25568 url: "your-url.php",
25569 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25570 callback: yourFunction,
25571 scope: yourObject, //(optional scope)
25574 text: "Loading...",
25579 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25580 * 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.
25581 * @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}
25582 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25583 * @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.
25586 var um = this.el.getUpdateManager();
25587 um.update.apply(um, arguments);
25590 render : function(el, response){
25591 this.clearSelections();
25592 this.el.update("");
25595 o = Roo.util.JSON.decode(response.responseText);
25598 o = o[this.jsonRoot];
25603 * The current JSON data or null
25606 this.beforeRender();
25611 * Get the number of records in the current JSON dataset
25614 getCount : function(){
25615 return this.jsonData ? this.jsonData.length : 0;
25619 * Returns the JSON object for the specified node(s)
25620 * @param {HTMLElement/Array} node The node or an array of nodes
25621 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25622 * you get the JSON object for the node
25624 getNodeData : function(node){
25625 if(node instanceof Array){
25627 for(var i = 0, len = node.length; i < len; i++){
25628 data.push(this.getNodeData(node[i]));
25632 return this.jsonData[this.indexOf(node)] || null;
25635 beforeRender : function(){
25636 this.snapshot = this.jsonData;
25638 this.sort.apply(this, this.sortInfo);
25640 this.fireEvent("beforerender", this, this.jsonData);
25643 onLoad : function(el, o){
25644 this.fireEvent("load", this, this.jsonData, o);
25647 onLoadException : function(el, o){
25648 this.fireEvent("loadexception", this, o);
25652 * Filter the data by a specific property.
25653 * @param {String} property A property on your JSON objects
25654 * @param {String/RegExp} value Either string that the property values
25655 * should start with, or a RegExp to test against the property
25657 filter : function(property, value){
25660 var ss = this.snapshot;
25661 if(typeof value == "string"){
25662 var vlen = value.length;
25664 this.clearFilter();
25667 value = value.toLowerCase();
25668 for(var i = 0, len = ss.length; i < len; i++){
25670 if(o[property].substr(0, vlen).toLowerCase() == value){
25674 } else if(value.exec){ // regex?
25675 for(var i = 0, len = ss.length; i < len; i++){
25677 if(value.test(o[property])){
25684 this.jsonData = data;
25690 * Filter by a function. The passed function will be called with each
25691 * object in the current dataset. If the function returns true the value is kept,
25692 * otherwise it is filtered.
25693 * @param {Function} fn
25694 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25696 filterBy : function(fn, scope){
25699 var ss = this.snapshot;
25700 for(var i = 0, len = ss.length; i < len; i++){
25702 if(fn.call(scope || this, o)){
25706 this.jsonData = data;
25712 * Clears the current filter.
25714 clearFilter : function(){
25715 if(this.snapshot && this.jsonData != this.snapshot){
25716 this.jsonData = this.snapshot;
25723 * Sorts the data for this view and refreshes it.
25724 * @param {String} property A property on your JSON objects to sort on
25725 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25726 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25728 sort : function(property, dir, sortType){
25729 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25732 var dsc = dir && dir.toLowerCase() == "desc";
25733 var f = function(o1, o2){
25734 var v1 = sortType ? sortType(o1[p]) : o1[p];
25735 var v2 = sortType ? sortType(o2[p]) : o2[p];
25738 return dsc ? +1 : -1;
25739 } else if(v1 > v2){
25740 return dsc ? -1 : +1;
25745 this.jsonData.sort(f);
25747 if(this.jsonData != this.snapshot){
25748 this.snapshot.sort(f);
25754 * Ext JS Library 1.1.1
25755 * Copyright(c) 2006-2007, Ext JS, LLC.
25757 * Originally Released Under LGPL - original licence link has changed is not relivant.
25760 * <script type="text/javascript">
25765 * @class Roo.ColorPalette
25766 * @extends Roo.Component
25767 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25768 * Here's an example of typical usage:
25770 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25771 cp.render('my-div');
25773 cp.on('select', function(palette, selColor){
25774 // do something with selColor
25778 * Create a new ColorPalette
25779 * @param {Object} config The config object
25781 Roo.ColorPalette = function(config){
25782 Roo.ColorPalette.superclass.constructor.call(this, config);
25786 * Fires when a color is selected
25787 * @param {ColorPalette} this
25788 * @param {String} color The 6-digit color hex code (without the # symbol)
25794 this.on("select", this.handler, this.scope, true);
25797 Roo.extend(Roo.ColorPalette, Roo.Component, {
25799 * @cfg {String} itemCls
25800 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25802 itemCls : "x-color-palette",
25804 * @cfg {String} value
25805 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25806 * the hex codes are case-sensitive.
25809 clickEvent:'click',
25811 ctype: "Roo.ColorPalette",
25814 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25816 allowReselect : false,
25819 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25820 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25821 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25822 * of colors with the width setting until the box is symmetrical.</p>
25823 * <p>You can override individual colors if needed:</p>
25825 var cp = new Roo.ColorPalette();
25826 cp.colors[0] = "FF0000"; // change the first box to red
25829 Or you can provide a custom array of your own for complete control:
25831 var cp = new Roo.ColorPalette();
25832 cp.colors = ["000000", "993300", "333300"];
25837 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25838 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25839 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25840 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25841 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25845 onRender : function(container, position){
25846 var t = new Roo.MasterTemplate(
25847 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25849 var c = this.colors;
25850 for(var i = 0, len = c.length; i < len; i++){
25853 var el = document.createElement("div");
25854 el.className = this.itemCls;
25856 container.dom.insertBefore(el, position);
25857 this.el = Roo.get(el);
25858 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25859 if(this.clickEvent != 'click'){
25860 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25865 afterRender : function(){
25866 Roo.ColorPalette.superclass.afterRender.call(this);
25868 var s = this.value;
25875 handleClick : function(e, t){
25876 e.preventDefault();
25877 if(!this.disabled){
25878 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25879 this.select(c.toUpperCase());
25884 * Selects the specified color in the palette (fires the select event)
25885 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25887 select : function(color){
25888 color = color.replace("#", "");
25889 if(color != this.value || this.allowReselect){
25892 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25894 el.child("a.color-"+color).addClass("x-color-palette-sel");
25895 this.value = color;
25896 this.fireEvent("select", this, color);
25901 * Ext JS Library 1.1.1
25902 * Copyright(c) 2006-2007, Ext JS, LLC.
25904 * Originally Released Under LGPL - original licence link has changed is not relivant.
25907 * <script type="text/javascript">
25911 * @class Roo.DatePicker
25912 * @extends Roo.Component
25913 * Simple date picker class.
25915 * Create a new DatePicker
25916 * @param {Object} config The config object
25918 Roo.DatePicker = function(config){
25919 Roo.DatePicker.superclass.constructor.call(this, config);
25921 this.value = config && config.value ?
25922 config.value.clearTime() : new Date().clearTime();
25927 * Fires when a date is selected
25928 * @param {DatePicker} this
25929 * @param {Date} date The selected date
25933 * @event monthchange
25934 * Fires when the displayed month changes
25935 * @param {DatePicker} this
25936 * @param {Date} date The selected month
25938 'monthchange': true
25942 this.on("select", this.handler, this.scope || this);
25944 // build the disabledDatesRE
25945 if(!this.disabledDatesRE && this.disabledDates){
25946 var dd = this.disabledDates;
25948 for(var i = 0; i < dd.length; i++){
25950 if(i != dd.length-1) re += "|";
25952 this.disabledDatesRE = new RegExp(re + ")");
25956 Roo.extend(Roo.DatePicker, Roo.Component, {
25958 * @cfg {String} todayText
25959 * The text to display on the button that selects the current date (defaults to "Today")
25961 todayText : "Today",
25963 * @cfg {String} okText
25964 * The text to display on the ok button
25966 okText : " OK ", //   to give the user extra clicking room
25968 * @cfg {String} cancelText
25969 * The text to display on the cancel button
25971 cancelText : "Cancel",
25973 * @cfg {String} todayTip
25974 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25976 todayTip : "{0} (Spacebar)",
25978 * @cfg {Date} minDate
25979 * Minimum allowable date (JavaScript date object, defaults to null)
25983 * @cfg {Date} maxDate
25984 * Maximum allowable date (JavaScript date object, defaults to null)
25988 * @cfg {String} minText
25989 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25991 minText : "This date is before the minimum date",
25993 * @cfg {String} maxText
25994 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25996 maxText : "This date is after the maximum date",
25998 * @cfg {String} format
25999 * The default date format string which can be overriden for localization support. The format must be
26000 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26004 * @cfg {Array} disabledDays
26005 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26007 disabledDays : null,
26009 * @cfg {String} disabledDaysText
26010 * The tooltip to display when the date falls on a disabled day (defaults to "")
26012 disabledDaysText : "",
26014 * @cfg {RegExp} disabledDatesRE
26015 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26017 disabledDatesRE : null,
26019 * @cfg {String} disabledDatesText
26020 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26022 disabledDatesText : "",
26024 * @cfg {Boolean} constrainToViewport
26025 * True to constrain the date picker to the viewport (defaults to true)
26027 constrainToViewport : true,
26029 * @cfg {Array} monthNames
26030 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26032 monthNames : Date.monthNames,
26034 * @cfg {Array} dayNames
26035 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26037 dayNames : Date.dayNames,
26039 * @cfg {String} nextText
26040 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26042 nextText: 'Next Month (Control+Right)',
26044 * @cfg {String} prevText
26045 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26047 prevText: 'Previous Month (Control+Left)',
26049 * @cfg {String} monthYearText
26050 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26052 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26054 * @cfg {Number} startDay
26055 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26059 * @cfg {Bool} showClear
26060 * Show a clear button (usefull for date form elements that can be blank.)
26066 * Sets the value of the date field
26067 * @param {Date} value The date to set
26069 setValue : function(value){
26070 var old = this.value;
26072 if (typeof(value) == 'string') {
26074 value = Date.parseDate(value, this.format);
26077 value = new Date();
26080 this.value = value.clearTime(true);
26082 this.update(this.value);
26087 * Gets the current selected value of the date field
26088 * @return {Date} The selected date
26090 getValue : function(){
26095 focus : function(){
26097 this.update(this.activeDate);
26102 onRender : function(container, position){
26105 '<table cellspacing="0">',
26106 '<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>',
26107 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26108 var dn = this.dayNames;
26109 for(var i = 0; i < 7; i++){
26110 var d = this.startDay+i;
26114 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26116 m[m.length] = "</tr></thead><tbody><tr>";
26117 for(var i = 0; i < 42; i++) {
26118 if(i % 7 == 0 && i != 0){
26119 m[m.length] = "</tr><tr>";
26121 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26123 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26124 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26126 var el = document.createElement("div");
26127 el.className = "x-date-picker";
26128 el.innerHTML = m.join("");
26130 container.dom.insertBefore(el, position);
26132 this.el = Roo.get(el);
26133 this.eventEl = Roo.get(el.firstChild);
26135 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26136 handler: this.showPrevMonth,
26138 preventDefault:true,
26142 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26143 handler: this.showNextMonth,
26145 preventDefault:true,
26149 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26151 this.monthPicker = this.el.down('div.x-date-mp');
26152 this.monthPicker.enableDisplayMode('block');
26154 var kn = new Roo.KeyNav(this.eventEl, {
26155 "left" : function(e){
26157 this.showPrevMonth() :
26158 this.update(this.activeDate.add("d", -1));
26161 "right" : function(e){
26163 this.showNextMonth() :
26164 this.update(this.activeDate.add("d", 1));
26167 "up" : function(e){
26169 this.showNextYear() :
26170 this.update(this.activeDate.add("d", -7));
26173 "down" : function(e){
26175 this.showPrevYear() :
26176 this.update(this.activeDate.add("d", 7));
26179 "pageUp" : function(e){
26180 this.showNextMonth();
26183 "pageDown" : function(e){
26184 this.showPrevMonth();
26187 "enter" : function(e){
26188 e.stopPropagation();
26195 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26197 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26199 this.el.unselectable();
26201 this.cells = this.el.select("table.x-date-inner tbody td");
26202 this.textNodes = this.el.query("table.x-date-inner tbody span");
26204 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26206 tooltip: this.monthYearText
26209 this.mbtn.on('click', this.showMonthPicker, this);
26210 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26213 var today = (new Date()).dateFormat(this.format);
26215 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26216 if (this.showClear) {
26217 baseTb.add( new Roo.Toolbar.Fill());
26220 text: String.format(this.todayText, today),
26221 tooltip: String.format(this.todayTip, today),
26222 handler: this.selectToday,
26226 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26229 if (this.showClear) {
26231 baseTb.add( new Roo.Toolbar.Fill());
26234 cls: 'x-btn-icon x-btn-clear',
26235 handler: function() {
26237 this.fireEvent("select", this, '');
26247 this.update(this.value);
26250 createMonthPicker : function(){
26251 if(!this.monthPicker.dom.firstChild){
26252 var buf = ['<table border="0" cellspacing="0">'];
26253 for(var i = 0; i < 6; i++){
26255 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26256 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26258 '<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>' :
26259 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26263 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26265 '</button><button type="button" class="x-date-mp-cancel">',
26267 '</button></td></tr>',
26270 this.monthPicker.update(buf.join(''));
26271 this.monthPicker.on('click', this.onMonthClick, this);
26272 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26274 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26275 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26277 this.mpMonths.each(function(m, a, i){
26280 m.dom.xmonth = 5 + Math.round(i * .5);
26282 m.dom.xmonth = Math.round((i-1) * .5);
26288 showMonthPicker : function(){
26289 this.createMonthPicker();
26290 var size = this.el.getSize();
26291 this.monthPicker.setSize(size);
26292 this.monthPicker.child('table').setSize(size);
26294 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26295 this.updateMPMonth(this.mpSelMonth);
26296 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26297 this.updateMPYear(this.mpSelYear);
26299 this.monthPicker.slideIn('t', {duration:.2});
26302 updateMPYear : function(y){
26304 var ys = this.mpYears.elements;
26305 for(var i = 1; i <= 10; i++){
26306 var td = ys[i-1], y2;
26308 y2 = y + Math.round(i * .5);
26309 td.firstChild.innerHTML = y2;
26312 y2 = y - (5-Math.round(i * .5));
26313 td.firstChild.innerHTML = y2;
26316 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26320 updateMPMonth : function(sm){
26321 this.mpMonths.each(function(m, a, i){
26322 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26326 selectMPMonth: function(m){
26330 onMonthClick : function(e, t){
26332 var el = new Roo.Element(t), pn;
26333 if(el.is('button.x-date-mp-cancel')){
26334 this.hideMonthPicker();
26336 else if(el.is('button.x-date-mp-ok')){
26337 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26338 this.hideMonthPicker();
26340 else if(pn = el.up('td.x-date-mp-month', 2)){
26341 this.mpMonths.removeClass('x-date-mp-sel');
26342 pn.addClass('x-date-mp-sel');
26343 this.mpSelMonth = pn.dom.xmonth;
26345 else if(pn = el.up('td.x-date-mp-year', 2)){
26346 this.mpYears.removeClass('x-date-mp-sel');
26347 pn.addClass('x-date-mp-sel');
26348 this.mpSelYear = pn.dom.xyear;
26350 else if(el.is('a.x-date-mp-prev')){
26351 this.updateMPYear(this.mpyear-10);
26353 else if(el.is('a.x-date-mp-next')){
26354 this.updateMPYear(this.mpyear+10);
26358 onMonthDblClick : function(e, t){
26360 var el = new Roo.Element(t), pn;
26361 if(pn = el.up('td.x-date-mp-month', 2)){
26362 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26363 this.hideMonthPicker();
26365 else if(pn = el.up('td.x-date-mp-year', 2)){
26366 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26367 this.hideMonthPicker();
26371 hideMonthPicker : function(disableAnim){
26372 if(this.monthPicker){
26373 if(disableAnim === true){
26374 this.monthPicker.hide();
26376 this.monthPicker.slideOut('t', {duration:.2});
26382 showPrevMonth : function(e){
26383 this.update(this.activeDate.add("mo", -1));
26387 showNextMonth : function(e){
26388 this.update(this.activeDate.add("mo", 1));
26392 showPrevYear : function(){
26393 this.update(this.activeDate.add("y", -1));
26397 showNextYear : function(){
26398 this.update(this.activeDate.add("y", 1));
26402 handleMouseWheel : function(e){
26403 var delta = e.getWheelDelta();
26405 this.showPrevMonth();
26407 } else if(delta < 0){
26408 this.showNextMonth();
26414 handleDateClick : function(e, t){
26416 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26417 this.setValue(new Date(t.dateValue));
26418 this.fireEvent("select", this, this.value);
26423 selectToday : function(){
26424 this.setValue(new Date().clearTime());
26425 this.fireEvent("select", this, this.value);
26429 update : function(date)
26431 var vd = this.activeDate;
26432 this.activeDate = date;
26434 var t = date.getTime();
26435 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26436 this.cells.removeClass("x-date-selected");
26437 this.cells.each(function(c){
26438 if(c.dom.firstChild.dateValue == t){
26439 c.addClass("x-date-selected");
26440 setTimeout(function(){
26441 try{c.dom.firstChild.focus();}catch(e){}
26450 var days = date.getDaysInMonth();
26451 var firstOfMonth = date.getFirstDateOfMonth();
26452 var startingPos = firstOfMonth.getDay()-this.startDay;
26454 if(startingPos <= this.startDay){
26458 var pm = date.add("mo", -1);
26459 var prevStart = pm.getDaysInMonth()-startingPos;
26461 var cells = this.cells.elements;
26462 var textEls = this.textNodes;
26463 days += startingPos;
26465 // convert everything to numbers so it's fast
26466 var day = 86400000;
26467 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26468 var today = new Date().clearTime().getTime();
26469 var sel = date.clearTime().getTime();
26470 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26471 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26472 var ddMatch = this.disabledDatesRE;
26473 var ddText = this.disabledDatesText;
26474 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26475 var ddaysText = this.disabledDaysText;
26476 var format = this.format;
26478 var setCellClass = function(cal, cell){
26480 var t = d.getTime();
26481 cell.firstChild.dateValue = t;
26483 cell.className += " x-date-today";
26484 cell.title = cal.todayText;
26487 cell.className += " x-date-selected";
26488 setTimeout(function(){
26489 try{cell.firstChild.focus();}catch(e){}
26494 cell.className = " x-date-disabled";
26495 cell.title = cal.minText;
26499 cell.className = " x-date-disabled";
26500 cell.title = cal.maxText;
26504 if(ddays.indexOf(d.getDay()) != -1){
26505 cell.title = ddaysText;
26506 cell.className = " x-date-disabled";
26509 if(ddMatch && format){
26510 var fvalue = d.dateFormat(format);
26511 if(ddMatch.test(fvalue)){
26512 cell.title = ddText.replace("%0", fvalue);
26513 cell.className = " x-date-disabled";
26519 for(; i < startingPos; i++) {
26520 textEls[i].innerHTML = (++prevStart);
26521 d.setDate(d.getDate()+1);
26522 cells[i].className = "x-date-prevday";
26523 setCellClass(this, cells[i]);
26525 for(; i < days; i++){
26526 intDay = i - startingPos + 1;
26527 textEls[i].innerHTML = (intDay);
26528 d.setDate(d.getDate()+1);
26529 cells[i].className = "x-date-active";
26530 setCellClass(this, cells[i]);
26533 for(; i < 42; i++) {
26534 textEls[i].innerHTML = (++extraDays);
26535 d.setDate(d.getDate()+1);
26536 cells[i].className = "x-date-nextday";
26537 setCellClass(this, cells[i]);
26540 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26541 this.fireEvent('monthchange', this, date);
26543 if(!this.internalRender){
26544 var main = this.el.dom.firstChild;
26545 var w = main.offsetWidth;
26546 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26547 Roo.fly(main).setWidth(w);
26548 this.internalRender = true;
26549 // opera does not respect the auto grow header center column
26550 // then, after it gets a width opera refuses to recalculate
26551 // without a second pass
26552 if(Roo.isOpera && !this.secondPass){
26553 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26554 this.secondPass = true;
26555 this.update.defer(10, this, [date]);
26563 * Ext JS Library 1.1.1
26564 * Copyright(c) 2006-2007, Ext JS, LLC.
26566 * Originally Released Under LGPL - original licence link has changed is not relivant.
26569 * <script type="text/javascript">
26572 * @class Roo.TabPanel
26573 * @extends Roo.util.Observable
26574 * A lightweight tab container.
26578 // basic tabs 1, built from existing content
26579 var tabs = new Roo.TabPanel("tabs1");
26580 tabs.addTab("script", "View Script");
26581 tabs.addTab("markup", "View Markup");
26582 tabs.activate("script");
26584 // more advanced tabs, built from javascript
26585 var jtabs = new Roo.TabPanel("jtabs");
26586 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26588 // set up the UpdateManager
26589 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26590 var updater = tab2.getUpdateManager();
26591 updater.setDefaultUrl("ajax1.htm");
26592 tab2.on('activate', updater.refresh, updater, true);
26594 // Use setUrl for Ajax loading
26595 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26596 tab3.setUrl("ajax2.htm", null, true);
26599 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26602 jtabs.activate("jtabs-1");
26605 * Create a new TabPanel.
26606 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26607 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26609 Roo.TabPanel = function(container, config){
26611 * The container element for this TabPanel.
26612 * @type Roo.Element
26614 this.el = Roo.get(container, true);
26616 if(typeof config == "boolean"){
26617 this.tabPosition = config ? "bottom" : "top";
26619 Roo.apply(this, config);
26622 if(this.tabPosition == "bottom"){
26623 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26624 this.el.addClass("x-tabs-bottom");
26626 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26627 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26628 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26630 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26632 if(this.tabPosition != "bottom"){
26633 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26634 * @type Roo.Element
26636 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26637 this.el.addClass("x-tabs-top");
26641 this.bodyEl.setStyle("position", "relative");
26643 this.active = null;
26644 this.activateDelegate = this.activate.createDelegate(this);
26649 * Fires when the active tab changes
26650 * @param {Roo.TabPanel} this
26651 * @param {Roo.TabPanelItem} activePanel The new active tab
26655 * @event beforetabchange
26656 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26657 * @param {Roo.TabPanel} this
26658 * @param {Object} e Set cancel to true on this object to cancel the tab change
26659 * @param {Roo.TabPanelItem} tab The tab being changed to
26661 "beforetabchange" : true
26664 Roo.EventManager.onWindowResize(this.onResize, this);
26665 this.cpad = this.el.getPadding("lr");
26666 this.hiddenCount = 0;
26669 // toolbar on the tabbar support...
26670 if (this.toolbar) {
26671 var tcfg = this.toolbar;
26672 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26673 this.toolbar = new Roo.Toolbar(tcfg);
26674 if (Roo.isSafari) {
26675 var tbl = tcfg.container.child('table', true);
26676 tbl.setAttribute('width', '100%');
26683 Roo.TabPanel.superclass.constructor.call(this);
26686 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26688 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26690 tabPosition : "top",
26692 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26694 currentTabWidth : 0,
26696 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26700 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26704 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26706 preferredTabWidth : 175,
26708 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26710 resizeTabs : false,
26712 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26714 monitorResize : true,
26716 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26721 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26722 * @param {String} id The id of the div to use <b>or create</b>
26723 * @param {String} text The text for the tab
26724 * @param {String} content (optional) Content to put in the TabPanelItem body
26725 * @param {Boolean} closable (optional) True to create a close icon on the tab
26726 * @return {Roo.TabPanelItem} The created TabPanelItem
26728 addTab : function(id, text, content, closable){
26729 var item = new Roo.TabPanelItem(this, id, text, closable);
26730 this.addTabItem(item);
26732 item.setContent(content);
26738 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26739 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26740 * @return {Roo.TabPanelItem}
26742 getTab : function(id){
26743 return this.items[id];
26747 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26748 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26750 hideTab : function(id){
26751 var t = this.items[id];
26754 this.hiddenCount++;
26755 this.autoSizeTabs();
26760 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26761 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26763 unhideTab : function(id){
26764 var t = this.items[id];
26766 t.setHidden(false);
26767 this.hiddenCount--;
26768 this.autoSizeTabs();
26773 * Adds an existing {@link Roo.TabPanelItem}.
26774 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26776 addTabItem : function(item){
26777 this.items[item.id] = item;
26778 this.items.push(item);
26779 if(this.resizeTabs){
26780 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26781 this.autoSizeTabs();
26788 * Removes a {@link Roo.TabPanelItem}.
26789 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26791 removeTab : function(id){
26792 var items = this.items;
26793 var tab = items[id];
26794 if(!tab) { return; }
26795 var index = items.indexOf(tab);
26796 if(this.active == tab && items.length > 1){
26797 var newTab = this.getNextAvailable(index);
26802 this.stripEl.dom.removeChild(tab.pnode.dom);
26803 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26804 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26806 items.splice(index, 1);
26807 delete this.items[tab.id];
26808 tab.fireEvent("close", tab);
26809 tab.purgeListeners();
26810 this.autoSizeTabs();
26813 getNextAvailable : function(start){
26814 var items = this.items;
26816 // look for a next tab that will slide over to
26817 // replace the one being removed
26818 while(index < items.length){
26819 var item = items[++index];
26820 if(item && !item.isHidden()){
26824 // if one isn't found select the previous tab (on the left)
26827 var item = items[--index];
26828 if(item && !item.isHidden()){
26836 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26837 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26839 disableTab : function(id){
26840 var tab = this.items[id];
26841 if(tab && this.active != tab){
26847 * Enables a {@link Roo.TabPanelItem} that is disabled.
26848 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26850 enableTab : function(id){
26851 var tab = this.items[id];
26856 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26857 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26858 * @return {Roo.TabPanelItem} The TabPanelItem.
26860 activate : function(id){
26861 var tab = this.items[id];
26865 if(tab == this.active || tab.disabled){
26869 this.fireEvent("beforetabchange", this, e, tab);
26870 if(e.cancel !== true && !tab.disabled){
26872 this.active.hide();
26874 this.active = this.items[id];
26875 this.active.show();
26876 this.fireEvent("tabchange", this, this.active);
26882 * Gets the active {@link Roo.TabPanelItem}.
26883 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26885 getActiveTab : function(){
26886 return this.active;
26890 * Updates the tab body element to fit the height of the container element
26891 * for overflow scrolling
26892 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26894 syncHeight : function(targetHeight){
26895 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26896 var bm = this.bodyEl.getMargins();
26897 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26898 this.bodyEl.setHeight(newHeight);
26902 onResize : function(){
26903 if(this.monitorResize){
26904 this.autoSizeTabs();
26909 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26911 beginUpdate : function(){
26912 this.updating = true;
26916 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26918 endUpdate : function(){
26919 this.updating = false;
26920 this.autoSizeTabs();
26924 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26926 autoSizeTabs : function(){
26927 var count = this.items.length;
26928 var vcount = count - this.hiddenCount;
26929 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26930 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26931 var availWidth = Math.floor(w / vcount);
26932 var b = this.stripBody;
26933 if(b.getWidth() > w){
26934 var tabs = this.items;
26935 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26936 if(availWidth < this.minTabWidth){
26937 /*if(!this.sleft){ // incomplete scrolling code
26938 this.createScrollButtons();
26941 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26944 if(this.currentTabWidth < this.preferredTabWidth){
26945 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26951 * Returns the number of tabs in this TabPanel.
26954 getCount : function(){
26955 return this.items.length;
26959 * Resizes all the tabs to the passed width
26960 * @param {Number} The new width
26962 setTabWidth : function(width){
26963 this.currentTabWidth = width;
26964 for(var i = 0, len = this.items.length; i < len; i++) {
26965 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26970 * Destroys this TabPanel
26971 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26973 destroy : function(removeEl){
26974 Roo.EventManager.removeResizeListener(this.onResize, this);
26975 for(var i = 0, len = this.items.length; i < len; i++){
26976 this.items[i].purgeListeners();
26978 if(removeEl === true){
26979 this.el.update("");
26986 * @class Roo.TabPanelItem
26987 * @extends Roo.util.Observable
26988 * Represents an individual item (tab plus body) in a TabPanel.
26989 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26990 * @param {String} id The id of this TabPanelItem
26991 * @param {String} text The text for the tab of this TabPanelItem
26992 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26994 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26996 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26997 * @type Roo.TabPanel
26999 this.tabPanel = tabPanel;
27001 * The id for this TabPanelItem
27006 this.disabled = false;
27010 this.loaded = false;
27011 this.closable = closable;
27014 * The body element for this TabPanelItem.
27015 * @type Roo.Element
27017 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27018 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27019 this.bodyEl.setStyle("display", "block");
27020 this.bodyEl.setStyle("zoom", "1");
27023 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27025 this.el = Roo.get(els.el, true);
27026 this.inner = Roo.get(els.inner, true);
27027 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27028 this.pnode = Roo.get(els.el.parentNode, true);
27029 this.el.on("mousedown", this.onTabMouseDown, this);
27030 this.el.on("click", this.onTabClick, this);
27033 var c = Roo.get(els.close, true);
27034 c.dom.title = this.closeText;
27035 c.addClassOnOver("close-over");
27036 c.on("click", this.closeClick, this);
27042 * Fires when this tab becomes the active tab.
27043 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27044 * @param {Roo.TabPanelItem} this
27048 * @event beforeclose
27049 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27050 * @param {Roo.TabPanelItem} this
27051 * @param {Object} e Set cancel to true on this object to cancel the close.
27053 "beforeclose": true,
27056 * Fires when this tab is closed.
27057 * @param {Roo.TabPanelItem} this
27061 * @event deactivate
27062 * Fires when this tab is no longer the active tab.
27063 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27064 * @param {Roo.TabPanelItem} this
27066 "deactivate" : true
27068 this.hidden = false;
27070 Roo.TabPanelItem.superclass.constructor.call(this);
27073 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27074 purgeListeners : function(){
27075 Roo.util.Observable.prototype.purgeListeners.call(this);
27076 this.el.removeAllListeners();
27079 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27082 this.pnode.addClass("on");
27085 this.tabPanel.stripWrap.repaint();
27087 this.fireEvent("activate", this.tabPanel, this);
27091 * Returns true if this tab is the active tab.
27092 * @return {Boolean}
27094 isActive : function(){
27095 return this.tabPanel.getActiveTab() == this;
27099 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27102 this.pnode.removeClass("on");
27104 this.fireEvent("deactivate", this.tabPanel, this);
27107 hideAction : function(){
27108 this.bodyEl.hide();
27109 this.bodyEl.setStyle("position", "absolute");
27110 this.bodyEl.setLeft("-20000px");
27111 this.bodyEl.setTop("-20000px");
27114 showAction : function(){
27115 this.bodyEl.setStyle("position", "relative");
27116 this.bodyEl.setTop("");
27117 this.bodyEl.setLeft("");
27118 this.bodyEl.show();
27122 * Set the tooltip for the tab.
27123 * @param {String} tooltip The tab's tooltip
27125 setTooltip : function(text){
27126 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27127 this.textEl.dom.qtip = text;
27128 this.textEl.dom.removeAttribute('title');
27130 this.textEl.dom.title = text;
27134 onTabClick : function(e){
27135 e.preventDefault();
27136 this.tabPanel.activate(this.id);
27139 onTabMouseDown : function(e){
27140 e.preventDefault();
27141 this.tabPanel.activate(this.id);
27144 getWidth : function(){
27145 return this.inner.getWidth();
27148 setWidth : function(width){
27149 var iwidth = width - this.pnode.getPadding("lr");
27150 this.inner.setWidth(iwidth);
27151 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27152 this.pnode.setWidth(width);
27156 * Show or hide the tab
27157 * @param {Boolean} hidden True to hide or false to show.
27159 setHidden : function(hidden){
27160 this.hidden = hidden;
27161 this.pnode.setStyle("display", hidden ? "none" : "");
27165 * Returns true if this tab is "hidden"
27166 * @return {Boolean}
27168 isHidden : function(){
27169 return this.hidden;
27173 * Returns the text for this tab
27176 getText : function(){
27180 autoSize : function(){
27181 //this.el.beginMeasure();
27182 this.textEl.setWidth(1);
27184 * #2804 [new] Tabs in Roojs
27185 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27187 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27188 //this.el.endMeasure();
27192 * Sets the text for the tab (Note: this also sets the tooltip text)
27193 * @param {String} text The tab's text and tooltip
27195 setText : function(text){
27197 this.textEl.update(text);
27198 this.setTooltip(text);
27199 if(!this.tabPanel.resizeTabs){
27204 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27206 activate : function(){
27207 this.tabPanel.activate(this.id);
27211 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27213 disable : function(){
27214 if(this.tabPanel.active != this){
27215 this.disabled = true;
27216 this.pnode.addClass("disabled");
27221 * Enables this TabPanelItem if it was previously disabled.
27223 enable : function(){
27224 this.disabled = false;
27225 this.pnode.removeClass("disabled");
27229 * Sets the content for this TabPanelItem.
27230 * @param {String} content The content
27231 * @param {Boolean} loadScripts true to look for and load scripts
27233 setContent : function(content, loadScripts){
27234 this.bodyEl.update(content, loadScripts);
27238 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27239 * @return {Roo.UpdateManager} The UpdateManager
27241 getUpdateManager : function(){
27242 return this.bodyEl.getUpdateManager();
27246 * Set a URL to be used to load the content for this TabPanelItem.
27247 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27248 * @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)
27249 * @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)
27250 * @return {Roo.UpdateManager} The UpdateManager
27252 setUrl : function(url, params, loadOnce){
27253 if(this.refreshDelegate){
27254 this.un('activate', this.refreshDelegate);
27256 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27257 this.on("activate", this.refreshDelegate);
27258 return this.bodyEl.getUpdateManager();
27262 _handleRefresh : function(url, params, loadOnce){
27263 if(!loadOnce || !this.loaded){
27264 var updater = this.bodyEl.getUpdateManager();
27265 updater.update(url, params, this._setLoaded.createDelegate(this));
27270 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27271 * Will fail silently if the setUrl method has not been called.
27272 * This does not activate the panel, just updates its content.
27274 refresh : function(){
27275 if(this.refreshDelegate){
27276 this.loaded = false;
27277 this.refreshDelegate();
27282 _setLoaded : function(){
27283 this.loaded = true;
27287 closeClick : function(e){
27290 this.fireEvent("beforeclose", this, o);
27291 if(o.cancel !== true){
27292 this.tabPanel.removeTab(this.id);
27296 * The text displayed in the tooltip for the close icon.
27299 closeText : "Close this tab"
27303 Roo.TabPanel.prototype.createStrip = function(container){
27304 var strip = document.createElement("div");
27305 strip.className = "x-tabs-wrap";
27306 container.appendChild(strip);
27310 Roo.TabPanel.prototype.createStripList = function(strip){
27311 // div wrapper for retard IE
27312 // returns the "tr" element.
27313 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27314 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27315 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27316 return strip.firstChild.firstChild.firstChild.firstChild;
27319 Roo.TabPanel.prototype.createBody = function(container){
27320 var body = document.createElement("div");
27321 Roo.id(body, "tab-body");
27322 Roo.fly(body).addClass("x-tabs-body");
27323 container.appendChild(body);
27327 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27328 var body = Roo.getDom(id);
27330 body = document.createElement("div");
27333 Roo.fly(body).addClass("x-tabs-item-body");
27334 bodyEl.insertBefore(body, bodyEl.firstChild);
27338 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27339 var td = document.createElement("td");
27340 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27341 //stripEl.appendChild(td);
27343 td.className = "x-tabs-closable";
27344 if(!this.closeTpl){
27345 this.closeTpl = new Roo.Template(
27346 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27347 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27348 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27351 var el = this.closeTpl.overwrite(td, {"text": text});
27352 var close = el.getElementsByTagName("div")[0];
27353 var inner = el.getElementsByTagName("em")[0];
27354 return {"el": el, "close": close, "inner": inner};
27357 this.tabTpl = new Roo.Template(
27358 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27359 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27362 var el = this.tabTpl.overwrite(td, {"text": text});
27363 var inner = el.getElementsByTagName("em")[0];
27364 return {"el": el, "inner": inner};
27368 * Ext JS Library 1.1.1
27369 * Copyright(c) 2006-2007, Ext JS, LLC.
27371 * Originally Released Under LGPL - original licence link has changed is not relivant.
27374 * <script type="text/javascript">
27378 * @class Roo.Button
27379 * @extends Roo.util.Observable
27380 * Simple Button class
27381 * @cfg {String} text The button text
27382 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27383 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27384 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27385 * @cfg {Object} scope The scope of the handler
27386 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27387 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27388 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27389 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27390 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27391 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27392 applies if enableToggle = true)
27393 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27394 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27395 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27397 * Create a new button
27398 * @param {Object} config The config object
27400 Roo.Button = function(renderTo, config)
27404 renderTo = config.renderTo || false;
27407 Roo.apply(this, config);
27411 * Fires when this button is clicked
27412 * @param {Button} this
27413 * @param {EventObject} e The click event
27418 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27419 * @param {Button} this
27420 * @param {Boolean} pressed
27425 * Fires when the mouse hovers over the button
27426 * @param {Button} this
27427 * @param {Event} e The event object
27429 'mouseover' : true,
27432 * Fires when the mouse exits the button
27433 * @param {Button} this
27434 * @param {Event} e The event object
27439 * Fires when the button is rendered
27440 * @param {Button} this
27445 this.menu = Roo.menu.MenuMgr.get(this.menu);
27447 // register listeners first!! - so render can be captured..
27448 Roo.util.Observable.call(this);
27450 this.render(renderTo);
27456 Roo.extend(Roo.Button, Roo.util.Observable, {
27462 * Read-only. True if this button is hidden
27467 * Read-only. True if this button is disabled
27472 * Read-only. True if this button is pressed (only if enableToggle = true)
27478 * @cfg {Number} tabIndex
27479 * The DOM tabIndex for this button (defaults to undefined)
27481 tabIndex : undefined,
27484 * @cfg {Boolean} enableToggle
27485 * True to enable pressed/not pressed toggling (defaults to false)
27487 enableToggle: false,
27489 * @cfg {Mixed} menu
27490 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27494 * @cfg {String} menuAlign
27495 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27497 menuAlign : "tl-bl?",
27500 * @cfg {String} iconCls
27501 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27503 iconCls : undefined,
27505 * @cfg {String} type
27506 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27511 menuClassTarget: 'tr',
27514 * @cfg {String} clickEvent
27515 * The type of event to map to the button's event handler (defaults to 'click')
27517 clickEvent : 'click',
27520 * @cfg {Boolean} handleMouseEvents
27521 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27523 handleMouseEvents : true,
27526 * @cfg {String} tooltipType
27527 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27529 tooltipType : 'qtip',
27532 * @cfg {String} cls
27533 * A CSS class to apply to the button's main element.
27537 * @cfg {Roo.Template} template (Optional)
27538 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27539 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27540 * require code modifications if required elements (e.g. a button) aren't present.
27544 render : function(renderTo){
27546 if(this.hideParent){
27547 this.parentEl = Roo.get(renderTo);
27549 if(!this.dhconfig){
27550 if(!this.template){
27551 if(!Roo.Button.buttonTemplate){
27552 // hideous table template
27553 Roo.Button.buttonTemplate = new Roo.Template(
27554 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27555 '<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>',
27556 "</tr></tbody></table>");
27558 this.template = Roo.Button.buttonTemplate;
27560 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27561 var btnEl = btn.child("button:first");
27562 btnEl.on('focus', this.onFocus, this);
27563 btnEl.on('blur', this.onBlur, this);
27565 btn.addClass(this.cls);
27568 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27571 btnEl.addClass(this.iconCls);
27573 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27576 if(this.tabIndex !== undefined){
27577 btnEl.dom.tabIndex = this.tabIndex;
27580 if(typeof this.tooltip == 'object'){
27581 Roo.QuickTips.tips(Roo.apply({
27585 btnEl.dom[this.tooltipType] = this.tooltip;
27589 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27593 this.el.dom.id = this.el.id = this.id;
27596 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27597 this.menu.on("show", this.onMenuShow, this);
27598 this.menu.on("hide", this.onMenuHide, this);
27600 btn.addClass("x-btn");
27601 if(Roo.isIE && !Roo.isIE7){
27602 this.autoWidth.defer(1, this);
27606 if(this.handleMouseEvents){
27607 btn.on("mouseover", this.onMouseOver, this);
27608 btn.on("mouseout", this.onMouseOut, this);
27609 btn.on("mousedown", this.onMouseDown, this);
27611 btn.on(this.clickEvent, this.onClick, this);
27612 //btn.on("mouseup", this.onMouseUp, this);
27619 Roo.ButtonToggleMgr.register(this);
27621 this.el.addClass("x-btn-pressed");
27624 var repeater = new Roo.util.ClickRepeater(btn,
27625 typeof this.repeat == "object" ? this.repeat : {}
27627 repeater.on("click", this.onClick, this);
27630 this.fireEvent('render', this);
27634 * Returns the button's underlying element
27635 * @return {Roo.Element} The element
27637 getEl : function(){
27642 * Destroys this Button and removes any listeners.
27644 destroy : function(){
27645 Roo.ButtonToggleMgr.unregister(this);
27646 this.el.removeAllListeners();
27647 this.purgeListeners();
27652 autoWidth : function(){
27654 this.el.setWidth("auto");
27655 if(Roo.isIE7 && Roo.isStrict){
27656 var ib = this.el.child('button');
27657 if(ib && ib.getWidth() > 20){
27659 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27664 this.el.beginMeasure();
27666 if(this.el.getWidth() < this.minWidth){
27667 this.el.setWidth(this.minWidth);
27670 this.el.endMeasure();
27677 * Assigns this button's click handler
27678 * @param {Function} handler The function to call when the button is clicked
27679 * @param {Object} scope (optional) Scope for the function passed in
27681 setHandler : function(handler, scope){
27682 this.handler = handler;
27683 this.scope = scope;
27687 * Sets this button's text
27688 * @param {String} text The button text
27690 setText : function(text){
27693 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27699 * Gets the text for this button
27700 * @return {String} The button text
27702 getText : function(){
27710 this.hidden = false;
27712 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27720 this.hidden = true;
27722 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27727 * Convenience function for boolean show/hide
27728 * @param {Boolean} visible True to show, false to hide
27730 setVisible: function(visible){
27739 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27740 * @param {Boolean} state (optional) Force a particular state
27742 toggle : function(state){
27743 state = state === undefined ? !this.pressed : state;
27744 if(state != this.pressed){
27746 this.el.addClass("x-btn-pressed");
27747 this.pressed = true;
27748 this.fireEvent("toggle", this, true);
27750 this.el.removeClass("x-btn-pressed");
27751 this.pressed = false;
27752 this.fireEvent("toggle", this, false);
27754 if(this.toggleHandler){
27755 this.toggleHandler.call(this.scope || this, this, state);
27763 focus : function(){
27764 this.el.child('button:first').focus();
27768 * Disable this button
27770 disable : function(){
27772 this.el.addClass("x-btn-disabled");
27774 this.disabled = true;
27778 * Enable this button
27780 enable : function(){
27782 this.el.removeClass("x-btn-disabled");
27784 this.disabled = false;
27788 * Convenience function for boolean enable/disable
27789 * @param {Boolean} enabled True to enable, false to disable
27791 setDisabled : function(v){
27792 this[v !== true ? "enable" : "disable"]();
27796 onClick : function(e){
27798 e.preventDefault();
27803 if(!this.disabled){
27804 if(this.enableToggle){
27807 if(this.menu && !this.menu.isVisible()){
27808 this.menu.show(this.el, this.menuAlign);
27810 this.fireEvent("click", this, e);
27812 this.el.removeClass("x-btn-over");
27813 this.handler.call(this.scope || this, this, e);
27818 onMouseOver : function(e){
27819 if(!this.disabled){
27820 this.el.addClass("x-btn-over");
27821 this.fireEvent('mouseover', this, e);
27825 onMouseOut : function(e){
27826 if(!e.within(this.el, true)){
27827 this.el.removeClass("x-btn-over");
27828 this.fireEvent('mouseout', this, e);
27832 onFocus : function(e){
27833 if(!this.disabled){
27834 this.el.addClass("x-btn-focus");
27838 onBlur : function(e){
27839 this.el.removeClass("x-btn-focus");
27842 onMouseDown : function(e){
27843 if(!this.disabled && e.button == 0){
27844 this.el.addClass("x-btn-click");
27845 Roo.get(document).on('mouseup', this.onMouseUp, this);
27849 onMouseUp : function(e){
27851 this.el.removeClass("x-btn-click");
27852 Roo.get(document).un('mouseup', this.onMouseUp, this);
27856 onMenuShow : function(e){
27857 this.el.addClass("x-btn-menu-active");
27860 onMenuHide : function(e){
27861 this.el.removeClass("x-btn-menu-active");
27865 // Private utility class used by Button
27866 Roo.ButtonToggleMgr = function(){
27869 function toggleGroup(btn, state){
27871 var g = groups[btn.toggleGroup];
27872 for(var i = 0, l = g.length; i < l; i++){
27874 g[i].toggle(false);
27881 register : function(btn){
27882 if(!btn.toggleGroup){
27885 var g = groups[btn.toggleGroup];
27887 g = groups[btn.toggleGroup] = [];
27890 btn.on("toggle", toggleGroup);
27893 unregister : function(btn){
27894 if(!btn.toggleGroup){
27897 var g = groups[btn.toggleGroup];
27900 btn.un("toggle", toggleGroup);
27906 * Ext JS Library 1.1.1
27907 * Copyright(c) 2006-2007, Ext JS, LLC.
27909 * Originally Released Under LGPL - original licence link has changed is not relivant.
27912 * <script type="text/javascript">
27916 * @class Roo.SplitButton
27917 * @extends Roo.Button
27918 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27919 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27920 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27921 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27922 * @cfg {String} arrowTooltip The title attribute of the arrow
27924 * Create a new menu button
27925 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27926 * @param {Object} config The config object
27928 Roo.SplitButton = function(renderTo, config){
27929 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27931 * @event arrowclick
27932 * Fires when this button's arrow is clicked
27933 * @param {SplitButton} this
27934 * @param {EventObject} e The click event
27936 this.addEvents({"arrowclick":true});
27939 Roo.extend(Roo.SplitButton, Roo.Button, {
27940 render : function(renderTo){
27941 // this is one sweet looking template!
27942 var tpl = new Roo.Template(
27943 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27944 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27945 '<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>',
27946 "</tbody></table></td><td>",
27947 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27948 '<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>',
27949 "</tbody></table></td></tr></table>"
27951 var btn = tpl.append(renderTo, [this.text, this.type], true);
27952 var btnEl = btn.child("button");
27954 btn.addClass(this.cls);
27957 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27960 btnEl.addClass(this.iconCls);
27962 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27966 if(this.handleMouseEvents){
27967 btn.on("mouseover", this.onMouseOver, this);
27968 btn.on("mouseout", this.onMouseOut, this);
27969 btn.on("mousedown", this.onMouseDown, this);
27970 btn.on("mouseup", this.onMouseUp, this);
27972 btn.on(this.clickEvent, this.onClick, this);
27974 if(typeof this.tooltip == 'object'){
27975 Roo.QuickTips.tips(Roo.apply({
27979 btnEl.dom[this.tooltipType] = this.tooltip;
27982 if(this.arrowTooltip){
27983 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27992 this.el.addClass("x-btn-pressed");
27994 if(Roo.isIE && !Roo.isIE7){
27995 this.autoWidth.defer(1, this);
28000 this.menu.on("show", this.onMenuShow, this);
28001 this.menu.on("hide", this.onMenuHide, this);
28003 this.fireEvent('render', this);
28007 autoWidth : function(){
28009 var tbl = this.el.child("table:first");
28010 var tbl2 = this.el.child("table:last");
28011 this.el.setWidth("auto");
28012 tbl.setWidth("auto");
28013 if(Roo.isIE7 && Roo.isStrict){
28014 var ib = this.el.child('button:first');
28015 if(ib && ib.getWidth() > 20){
28017 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28022 this.el.beginMeasure();
28024 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28025 tbl.setWidth(this.minWidth-tbl2.getWidth());
28028 this.el.endMeasure();
28031 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28035 * Sets this button's click handler
28036 * @param {Function} handler The function to call when the button is clicked
28037 * @param {Object} scope (optional) Scope for the function passed above
28039 setHandler : function(handler, scope){
28040 this.handler = handler;
28041 this.scope = scope;
28045 * Sets this button's arrow click handler
28046 * @param {Function} handler The function to call when the arrow is clicked
28047 * @param {Object} scope (optional) Scope for the function passed above
28049 setArrowHandler : function(handler, scope){
28050 this.arrowHandler = handler;
28051 this.scope = scope;
28057 focus : function(){
28059 this.el.child("button:first").focus();
28064 onClick : function(e){
28065 e.preventDefault();
28066 if(!this.disabled){
28067 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28068 if(this.menu && !this.menu.isVisible()){
28069 this.menu.show(this.el, this.menuAlign);
28071 this.fireEvent("arrowclick", this, e);
28072 if(this.arrowHandler){
28073 this.arrowHandler.call(this.scope || this, this, e);
28076 this.fireEvent("click", this, e);
28078 this.handler.call(this.scope || this, this, e);
28084 onMouseDown : function(e){
28085 if(!this.disabled){
28086 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28090 onMouseUp : function(e){
28091 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28096 // backwards compat
28097 Roo.MenuButton = Roo.SplitButton;/*
28099 * Ext JS Library 1.1.1
28100 * Copyright(c) 2006-2007, Ext JS, LLC.
28102 * Originally Released Under LGPL - original licence link has changed is not relivant.
28105 * <script type="text/javascript">
28109 * @class Roo.Toolbar
28110 * Basic Toolbar class.
28112 * Creates a new Toolbar
28113 * @param {Object} container The config object
28115 Roo.Toolbar = function(container, buttons, config)
28117 /// old consturctor format still supported..
28118 if(container instanceof Array){ // omit the container for later rendering
28119 buttons = container;
28123 if (typeof(container) == 'object' && container.xtype) {
28124 config = container;
28125 container = config.container;
28126 buttons = config.buttons || []; // not really - use items!!
28129 if (config && config.items) {
28130 xitems = config.items;
28131 delete config.items;
28133 Roo.apply(this, config);
28134 this.buttons = buttons;
28137 this.render(container);
28139 this.xitems = xitems;
28140 Roo.each(xitems, function(b) {
28146 Roo.Toolbar.prototype = {
28148 * @cfg {Array} items
28149 * array of button configs or elements to add (will be converted to a MixedCollection)
28153 * @cfg {String/HTMLElement/Element} container
28154 * The id or element that will contain the toolbar
28157 render : function(ct){
28158 this.el = Roo.get(ct);
28160 this.el.addClass(this.cls);
28162 // using a table allows for vertical alignment
28163 // 100% width is needed by Safari...
28164 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28165 this.tr = this.el.child("tr", true);
28167 this.items = new Roo.util.MixedCollection(false, function(o){
28168 return o.id || ("item" + (++autoId));
28171 this.add.apply(this, this.buttons);
28172 delete this.buttons;
28177 * Adds element(s) to the toolbar -- this function takes a variable number of
28178 * arguments of mixed type and adds them to the toolbar.
28179 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28181 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28182 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28183 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28184 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28185 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28186 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28187 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28188 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28189 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28191 * @param {Mixed} arg2
28192 * @param {Mixed} etc.
28195 var a = arguments, l = a.length;
28196 for(var i = 0; i < l; i++){
28201 _add : function(el) {
28204 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28207 if (el.applyTo){ // some kind of form field
28208 return this.addField(el);
28210 if (el.render){ // some kind of Toolbar.Item
28211 return this.addItem(el);
28213 if (typeof el == "string"){ // string
28214 if(el == "separator" || el == "-"){
28215 return this.addSeparator();
28218 return this.addSpacer();
28221 return this.addFill();
28223 return this.addText(el);
28226 if(el.tagName){ // element
28227 return this.addElement(el);
28229 if(typeof el == "object"){ // must be button config?
28230 return this.addButton(el);
28232 // and now what?!?!
28238 * Add an Xtype element
28239 * @param {Object} xtype Xtype Object
28240 * @return {Object} created Object
28242 addxtype : function(e){
28243 return this.add(e);
28247 * Returns the Element for this toolbar.
28248 * @return {Roo.Element}
28250 getEl : function(){
28256 * @return {Roo.Toolbar.Item} The separator item
28258 addSeparator : function(){
28259 return this.addItem(new Roo.Toolbar.Separator());
28263 * Adds a spacer element
28264 * @return {Roo.Toolbar.Spacer} The spacer item
28266 addSpacer : function(){
28267 return this.addItem(new Roo.Toolbar.Spacer());
28271 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28272 * @return {Roo.Toolbar.Fill} The fill item
28274 addFill : function(){
28275 return this.addItem(new Roo.Toolbar.Fill());
28279 * Adds any standard HTML element to the toolbar
28280 * @param {String/HTMLElement/Element} el The element or id of the element to add
28281 * @return {Roo.Toolbar.Item} The element's item
28283 addElement : function(el){
28284 return this.addItem(new Roo.Toolbar.Item(el));
28287 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28288 * @type Roo.util.MixedCollection
28293 * Adds any Toolbar.Item or subclass
28294 * @param {Roo.Toolbar.Item} item
28295 * @return {Roo.Toolbar.Item} The item
28297 addItem : function(item){
28298 var td = this.nextBlock();
28300 this.items.add(item);
28305 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28306 * @param {Object/Array} config A button config or array of configs
28307 * @return {Roo.Toolbar.Button/Array}
28309 addButton : function(config){
28310 if(config instanceof Array){
28312 for(var i = 0, len = config.length; i < len; i++) {
28313 buttons.push(this.addButton(config[i]));
28318 if(!(config instanceof Roo.Toolbar.Button)){
28320 new Roo.Toolbar.SplitButton(config) :
28321 new Roo.Toolbar.Button(config);
28323 var td = this.nextBlock();
28330 * Adds text to the toolbar
28331 * @param {String} text The text to add
28332 * @return {Roo.Toolbar.Item} The element's item
28334 addText : function(text){
28335 return this.addItem(new Roo.Toolbar.TextItem(text));
28339 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28340 * @param {Number} index The index where the item is to be inserted
28341 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28342 * @return {Roo.Toolbar.Button/Item}
28344 insertButton : function(index, item){
28345 if(item instanceof Array){
28347 for(var i = 0, len = item.length; i < len; i++) {
28348 buttons.push(this.insertButton(index + i, item[i]));
28352 if (!(item instanceof Roo.Toolbar.Button)){
28353 item = new Roo.Toolbar.Button(item);
28355 var td = document.createElement("td");
28356 this.tr.insertBefore(td, this.tr.childNodes[index]);
28358 this.items.insert(index, item);
28363 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28364 * @param {Object} config
28365 * @return {Roo.Toolbar.Item} The element's item
28367 addDom : function(config, returnEl){
28368 var td = this.nextBlock();
28369 Roo.DomHelper.overwrite(td, config);
28370 var ti = new Roo.Toolbar.Item(td.firstChild);
28372 this.items.add(ti);
28377 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28378 * @type Roo.util.MixedCollection
28383 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28384 * Note: the field should not have been rendered yet. For a field that has already been
28385 * rendered, use {@link #addElement}.
28386 * @param {Roo.form.Field} field
28387 * @return {Roo.ToolbarItem}
28391 addField : function(field) {
28392 if (!this.fields) {
28394 this.fields = new Roo.util.MixedCollection(false, function(o){
28395 return o.id || ("item" + (++autoId));
28400 var td = this.nextBlock();
28402 var ti = new Roo.Toolbar.Item(td.firstChild);
28404 this.items.add(ti);
28405 this.fields.add(field);
28416 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28417 this.el.child('div').hide();
28425 this.el.child('div').show();
28429 nextBlock : function(){
28430 var td = document.createElement("td");
28431 this.tr.appendChild(td);
28436 destroy : function(){
28437 if(this.items){ // rendered?
28438 Roo.destroy.apply(Roo, this.items.items);
28440 if(this.fields){ // rendered?
28441 Roo.destroy.apply(Roo, this.fields.items);
28443 Roo.Element.uncache(this.el, this.tr);
28448 * @class Roo.Toolbar.Item
28449 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28451 * Creates a new Item
28452 * @param {HTMLElement} el
28454 Roo.Toolbar.Item = function(el){
28455 this.el = Roo.getDom(el);
28456 this.id = Roo.id(this.el);
28457 this.hidden = false;
28460 Roo.Toolbar.Item.prototype = {
28463 * Get this item's HTML Element
28464 * @return {HTMLElement}
28466 getEl : function(){
28471 render : function(td){
28473 td.appendChild(this.el);
28477 * Removes and destroys this item.
28479 destroy : function(){
28480 this.td.parentNode.removeChild(this.td);
28487 this.hidden = false;
28488 this.td.style.display = "";
28495 this.hidden = true;
28496 this.td.style.display = "none";
28500 * Convenience function for boolean show/hide.
28501 * @param {Boolean} visible true to show/false to hide
28503 setVisible: function(visible){
28512 * Try to focus this item.
28514 focus : function(){
28515 Roo.fly(this.el).focus();
28519 * Disables this item.
28521 disable : function(){
28522 Roo.fly(this.td).addClass("x-item-disabled");
28523 this.disabled = true;
28524 this.el.disabled = true;
28528 * Enables this item.
28530 enable : function(){
28531 Roo.fly(this.td).removeClass("x-item-disabled");
28532 this.disabled = false;
28533 this.el.disabled = false;
28539 * @class Roo.Toolbar.Separator
28540 * @extends Roo.Toolbar.Item
28541 * A simple toolbar separator class
28543 * Creates a new Separator
28545 Roo.Toolbar.Separator = function(){
28546 var s = document.createElement("span");
28547 s.className = "ytb-sep";
28548 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
28550 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28551 enable:Roo.emptyFn,
28552 disable:Roo.emptyFn,
28557 * @class Roo.Toolbar.Spacer
28558 * @extends Roo.Toolbar.Item
28559 * A simple element that adds extra horizontal space to a toolbar.
28561 * Creates a new Spacer
28563 Roo.Toolbar.Spacer = function(){
28564 var s = document.createElement("div");
28565 s.className = "ytb-spacer";
28566 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
28568 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28569 enable:Roo.emptyFn,
28570 disable:Roo.emptyFn,
28575 * @class Roo.Toolbar.Fill
28576 * @extends Roo.Toolbar.Spacer
28577 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28579 * Creates a new Spacer
28581 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28583 render : function(td){
28584 td.style.width = '100%';
28585 Roo.Toolbar.Fill.superclass.render.call(this, td);
28590 * @class Roo.Toolbar.TextItem
28591 * @extends Roo.Toolbar.Item
28592 * A simple class that renders text directly into a toolbar.
28594 * Creates a new TextItem
28595 * @param {String} text
28597 Roo.Toolbar.TextItem = function(text){
28598 if (typeof(text) == 'object') {
28601 var s = document.createElement("span");
28602 s.className = "ytb-text";
28603 s.innerHTML = text;
28604 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28606 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28607 enable:Roo.emptyFn,
28608 disable:Roo.emptyFn,
28613 * @class Roo.Toolbar.Button
28614 * @extends Roo.Button
28615 * A button that renders into a toolbar.
28617 * Creates a new Button
28618 * @param {Object} config A standard {@link Roo.Button} config object
28620 Roo.Toolbar.Button = function(config){
28621 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28623 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28624 render : function(td){
28626 Roo.Toolbar.Button.superclass.render.call(this, td);
28630 * Removes and destroys this button
28632 destroy : function(){
28633 Roo.Toolbar.Button.superclass.destroy.call(this);
28634 this.td.parentNode.removeChild(this.td);
28638 * Shows this button
28641 this.hidden = false;
28642 this.td.style.display = "";
28646 * Hides this button
28649 this.hidden = true;
28650 this.td.style.display = "none";
28654 * Disables this item
28656 disable : function(){
28657 Roo.fly(this.td).addClass("x-item-disabled");
28658 this.disabled = true;
28662 * Enables this item
28664 enable : function(){
28665 Roo.fly(this.td).removeClass("x-item-disabled");
28666 this.disabled = false;
28669 // backwards compat
28670 Roo.ToolbarButton = Roo.Toolbar.Button;
28673 * @class Roo.Toolbar.SplitButton
28674 * @extends Roo.SplitButton
28675 * A menu button that renders into a toolbar.
28677 * Creates a new SplitButton
28678 * @param {Object} config A standard {@link Roo.SplitButton} config object
28680 Roo.Toolbar.SplitButton = function(config){
28681 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28683 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28684 render : function(td){
28686 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28690 * Removes and destroys this button
28692 destroy : function(){
28693 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28694 this.td.parentNode.removeChild(this.td);
28698 * Shows this button
28701 this.hidden = false;
28702 this.td.style.display = "";
28706 * Hides this button
28709 this.hidden = true;
28710 this.td.style.display = "none";
28714 // backwards compat
28715 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28717 * Ext JS Library 1.1.1
28718 * Copyright(c) 2006-2007, Ext JS, LLC.
28720 * Originally Released Under LGPL - original licence link has changed is not relivant.
28723 * <script type="text/javascript">
28727 * @class Roo.PagingToolbar
28728 * @extends Roo.Toolbar
28729 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28731 * Create a new PagingToolbar
28732 * @param {Object} config The config object
28734 Roo.PagingToolbar = function(el, ds, config)
28736 // old args format still supported... - xtype is prefered..
28737 if (typeof(el) == 'object' && el.xtype) {
28738 // created from xtype...
28740 ds = el.dataSource;
28741 el = config.container;
28744 if (config.items) {
28745 items = config.items;
28749 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28752 this.renderButtons(this.el);
28755 // supprot items array.
28757 Roo.each(items, function(e) {
28758 this.add(Roo.factory(e));
28763 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28765 * @cfg {Roo.data.Store} dataSource
28766 * The underlying data store providing the paged data
28769 * @cfg {String/HTMLElement/Element} container
28770 * container The id or element that will contain the toolbar
28773 * @cfg {Boolean} displayInfo
28774 * True to display the displayMsg (defaults to false)
28777 * @cfg {Number} pageSize
28778 * The number of records to display per page (defaults to 20)
28782 * @cfg {String} displayMsg
28783 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28785 displayMsg : 'Displaying {0} - {1} of {2}',
28787 * @cfg {String} emptyMsg
28788 * The message to display when no records are found (defaults to "No data to display")
28790 emptyMsg : 'No data to display',
28792 * Customizable piece of the default paging text (defaults to "Page")
28795 beforePageText : "Page",
28797 * Customizable piece of the default paging text (defaults to "of %0")
28800 afterPageText : "of {0}",
28802 * Customizable piece of the default paging text (defaults to "First Page")
28805 firstText : "First Page",
28807 * Customizable piece of the default paging text (defaults to "Previous Page")
28810 prevText : "Previous Page",
28812 * Customizable piece of the default paging text (defaults to "Next Page")
28815 nextText : "Next Page",
28817 * Customizable piece of the default paging text (defaults to "Last Page")
28820 lastText : "Last Page",
28822 * Customizable piece of the default paging text (defaults to "Refresh")
28825 refreshText : "Refresh",
28828 renderButtons : function(el){
28829 Roo.PagingToolbar.superclass.render.call(this, el);
28830 this.first = this.addButton({
28831 tooltip: this.firstText,
28832 cls: "x-btn-icon x-grid-page-first",
28834 handler: this.onClick.createDelegate(this, ["first"])
28836 this.prev = this.addButton({
28837 tooltip: this.prevText,
28838 cls: "x-btn-icon x-grid-page-prev",
28840 handler: this.onClick.createDelegate(this, ["prev"])
28842 //this.addSeparator();
28843 this.add(this.beforePageText);
28844 this.field = Roo.get(this.addDom({
28849 cls: "x-grid-page-number"
28851 this.field.on("keydown", this.onPagingKeydown, this);
28852 this.field.on("focus", function(){this.dom.select();});
28853 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28854 this.field.setHeight(18);
28855 //this.addSeparator();
28856 this.next = this.addButton({
28857 tooltip: this.nextText,
28858 cls: "x-btn-icon x-grid-page-next",
28860 handler: this.onClick.createDelegate(this, ["next"])
28862 this.last = this.addButton({
28863 tooltip: this.lastText,
28864 cls: "x-btn-icon x-grid-page-last",
28866 handler: this.onClick.createDelegate(this, ["last"])
28868 //this.addSeparator();
28869 this.loading = this.addButton({
28870 tooltip: this.refreshText,
28871 cls: "x-btn-icon x-grid-loading",
28872 handler: this.onClick.createDelegate(this, ["refresh"])
28875 if(this.displayInfo){
28876 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28881 updateInfo : function(){
28882 if(this.displayEl){
28883 var count = this.ds.getCount();
28884 var msg = count == 0 ?
28888 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28890 this.displayEl.update(msg);
28895 onLoad : function(ds, r, o){
28896 this.cursor = o.params ? o.params.start : 0;
28897 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28899 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28900 this.field.dom.value = ap;
28901 this.first.setDisabled(ap == 1);
28902 this.prev.setDisabled(ap == 1);
28903 this.next.setDisabled(ap == ps);
28904 this.last.setDisabled(ap == ps);
28905 this.loading.enable();
28910 getPageData : function(){
28911 var total = this.ds.getTotalCount();
28914 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28915 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28920 onLoadError : function(){
28921 this.loading.enable();
28925 onPagingKeydown : function(e){
28926 var k = e.getKey();
28927 var d = this.getPageData();
28929 var v = this.field.dom.value, pageNum;
28930 if(!v || isNaN(pageNum = parseInt(v, 10))){
28931 this.field.dom.value = d.activePage;
28934 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28935 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28938 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))
28940 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28941 this.field.dom.value = pageNum;
28942 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28945 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28947 var v = this.field.dom.value, pageNum;
28948 var increment = (e.shiftKey) ? 10 : 1;
28949 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28951 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28952 this.field.dom.value = d.activePage;
28955 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28957 this.field.dom.value = parseInt(v, 10) + increment;
28958 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28959 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28966 beforeLoad : function(){
28968 this.loading.disable();
28973 onClick : function(which){
28977 ds.load({params:{start: 0, limit: this.pageSize}});
28980 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28983 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28986 var total = ds.getTotalCount();
28987 var extra = total % this.pageSize;
28988 var lastStart = extra ? (total - extra) : total-this.pageSize;
28989 ds.load({params:{start: lastStart, limit: this.pageSize}});
28992 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28998 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28999 * @param {Roo.data.Store} store The data store to unbind
29001 unbind : function(ds){
29002 ds.un("beforeload", this.beforeLoad, this);
29003 ds.un("load", this.onLoad, this);
29004 ds.un("loadexception", this.onLoadError, this);
29005 ds.un("remove", this.updateInfo, this);
29006 ds.un("add", this.updateInfo, this);
29007 this.ds = undefined;
29011 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29012 * @param {Roo.data.Store} store The data store to bind
29014 bind : function(ds){
29015 ds.on("beforeload", this.beforeLoad, this);
29016 ds.on("load", this.onLoad, this);
29017 ds.on("loadexception", this.onLoadError, this);
29018 ds.on("remove", this.updateInfo, this);
29019 ds.on("add", this.updateInfo, this);
29024 * Ext JS Library 1.1.1
29025 * Copyright(c) 2006-2007, Ext JS, LLC.
29027 * Originally Released Under LGPL - original licence link has changed is not relivant.
29030 * <script type="text/javascript">
29034 * @class Roo.Resizable
29035 * @extends Roo.util.Observable
29036 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29037 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29038 * 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
29039 * the element will be wrapped for you automatically.</p>
29040 * <p>Here is the list of valid resize handles:</p>
29043 ------ -------------------
29052 'hd' horizontal drag
29055 * <p>Here's an example showing the creation of a typical Resizable:</p>
29057 var resizer = new Roo.Resizable("element-id", {
29065 resizer.on("resize", myHandler);
29067 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29068 * resizer.east.setDisplayed(false);</p>
29069 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29070 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29071 * resize operation's new size (defaults to [0, 0])
29072 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29073 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29074 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29075 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29076 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29077 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29078 * @cfg {Number} width The width of the element in pixels (defaults to null)
29079 * @cfg {Number} height The height of the element in pixels (defaults to null)
29080 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29081 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29082 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29083 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29084 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29085 * in favor of the handles config option (defaults to false)
29086 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29087 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29088 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29089 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29090 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29091 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29092 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29093 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29094 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29095 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29096 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29098 * Create a new resizable component
29099 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29100 * @param {Object} config configuration options
29102 Roo.Resizable = function(el, config)
29104 this.el = Roo.get(el);
29106 if(config && config.wrap){
29107 config.resizeChild = this.el;
29108 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29109 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29110 this.el.setStyle("overflow", "hidden");
29111 this.el.setPositioning(config.resizeChild.getPositioning());
29112 config.resizeChild.clearPositioning();
29113 if(!config.width || !config.height){
29114 var csize = config.resizeChild.getSize();
29115 this.el.setSize(csize.width, csize.height);
29117 if(config.pinned && !config.adjustments){
29118 config.adjustments = "auto";
29122 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29123 this.proxy.unselectable();
29124 this.proxy.enableDisplayMode('block');
29126 Roo.apply(this, config);
29129 this.disableTrackOver = true;
29130 this.el.addClass("x-resizable-pinned");
29132 // if the element isn't positioned, make it relative
29133 var position = this.el.getStyle("position");
29134 if(position != "absolute" && position != "fixed"){
29135 this.el.setStyle("position", "relative");
29137 if(!this.handles){ // no handles passed, must be legacy style
29138 this.handles = 's,e,se';
29139 if(this.multiDirectional){
29140 this.handles += ',n,w';
29143 if(this.handles == "all"){
29144 this.handles = "n s e w ne nw se sw";
29146 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29147 var ps = Roo.Resizable.positions;
29148 for(var i = 0, len = hs.length; i < len; i++){
29149 if(hs[i] && ps[hs[i]]){
29150 var pos = ps[hs[i]];
29151 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29155 this.corner = this.southeast;
29157 // updateBox = the box can move..
29158 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29159 this.updateBox = true;
29162 this.activeHandle = null;
29164 if(this.resizeChild){
29165 if(typeof this.resizeChild == "boolean"){
29166 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29168 this.resizeChild = Roo.get(this.resizeChild, true);
29172 if(this.adjustments == "auto"){
29173 var rc = this.resizeChild;
29174 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29175 if(rc && (hw || hn)){
29176 rc.position("relative");
29177 rc.setLeft(hw ? hw.el.getWidth() : 0);
29178 rc.setTop(hn ? hn.el.getHeight() : 0);
29180 this.adjustments = [
29181 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29182 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29186 if(this.draggable){
29187 this.dd = this.dynamic ?
29188 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29189 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29195 * @event beforeresize
29196 * Fired before resize is allowed. Set enabled to false to cancel resize.
29197 * @param {Roo.Resizable} this
29198 * @param {Roo.EventObject} e The mousedown event
29200 "beforeresize" : true,
29203 * Fired a resizing.
29204 * @param {Roo.Resizable} this
29205 * @param {Number} x The new x position
29206 * @param {Number} y The new y position
29207 * @param {Number} w The new w width
29208 * @param {Number} h The new h hight
29209 * @param {Roo.EventObject} e The mouseup event
29214 * Fired after a resize.
29215 * @param {Roo.Resizable} this
29216 * @param {Number} width The new width
29217 * @param {Number} height The new height
29218 * @param {Roo.EventObject} e The mouseup event
29223 if(this.width !== null && this.height !== null){
29224 this.resizeTo(this.width, this.height);
29226 this.updateChildSize();
29229 this.el.dom.style.zoom = 1;
29231 Roo.Resizable.superclass.constructor.call(this);
29234 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29235 resizeChild : false,
29236 adjustments : [0, 0],
29246 multiDirectional : false,
29247 disableTrackOver : false,
29248 easing : 'easeOutStrong',
29249 widthIncrement : 0,
29250 heightIncrement : 0,
29254 preserveRatio : false,
29255 transparent: false,
29261 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29263 constrainTo: undefined,
29265 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29267 resizeRegion: undefined,
29271 * Perform a manual resize
29272 * @param {Number} width
29273 * @param {Number} height
29275 resizeTo : function(width, height){
29276 this.el.setSize(width, height);
29277 this.updateChildSize();
29278 this.fireEvent("resize", this, width, height, null);
29282 startSizing : function(e, handle){
29283 this.fireEvent("beforeresize", this, e);
29284 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29287 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29288 this.overlay.unselectable();
29289 this.overlay.enableDisplayMode("block");
29290 this.overlay.on("mousemove", this.onMouseMove, this);
29291 this.overlay.on("mouseup", this.onMouseUp, this);
29293 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29295 this.resizing = true;
29296 this.startBox = this.el.getBox();
29297 this.startPoint = e.getXY();
29298 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29299 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29301 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29302 this.overlay.show();
29304 if(this.constrainTo) {
29305 var ct = Roo.get(this.constrainTo);
29306 this.resizeRegion = ct.getRegion().adjust(
29307 ct.getFrameWidth('t'),
29308 ct.getFrameWidth('l'),
29309 -ct.getFrameWidth('b'),
29310 -ct.getFrameWidth('r')
29314 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29316 this.proxy.setBox(this.startBox);
29318 this.proxy.setStyle('visibility', 'visible');
29324 onMouseDown : function(handle, e){
29327 this.activeHandle = handle;
29328 this.startSizing(e, handle);
29333 onMouseUp : function(e){
29334 var size = this.resizeElement();
29335 this.resizing = false;
29337 this.overlay.hide();
29339 this.fireEvent("resize", this, size.width, size.height, e);
29343 updateChildSize : function(){
29345 if(this.resizeChild){
29347 var child = this.resizeChild;
29348 var adj = this.adjustments;
29349 if(el.dom.offsetWidth){
29350 var b = el.getSize(true);
29351 child.setSize(b.width+adj[0], b.height+adj[1]);
29353 // Second call here for IE
29354 // The first call enables instant resizing and
29355 // the second call corrects scroll bars if they
29358 setTimeout(function(){
29359 if(el.dom.offsetWidth){
29360 var b = el.getSize(true);
29361 child.setSize(b.width+adj[0], b.height+adj[1]);
29369 snap : function(value, inc, min){
29370 if(!inc || !value) return value;
29371 var newValue = value;
29372 var m = value % inc;
29375 newValue = value + (inc-m);
29377 newValue = value - m;
29380 return Math.max(min, newValue);
29384 resizeElement : function(){
29385 var box = this.proxy.getBox();
29386 if(this.updateBox){
29387 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29389 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29391 this.updateChildSize();
29399 constrain : function(v, diff, m, mx){
29402 }else if(v - diff > mx){
29409 onMouseMove : function(e){
29412 try{// try catch so if something goes wrong the user doesn't get hung
29414 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29418 //var curXY = this.startPoint;
29419 var curSize = this.curSize || this.startBox;
29420 var x = this.startBox.x, y = this.startBox.y;
29421 var ox = x, oy = y;
29422 var w = curSize.width, h = curSize.height;
29423 var ow = w, oh = h;
29424 var mw = this.minWidth, mh = this.minHeight;
29425 var mxw = this.maxWidth, mxh = this.maxHeight;
29426 var wi = this.widthIncrement;
29427 var hi = this.heightIncrement;
29429 var eventXY = e.getXY();
29430 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29431 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29433 var pos = this.activeHandle.position;
29438 w = Math.min(Math.max(mw, w), mxw);
29443 h = Math.min(Math.max(mh, h), mxh);
29448 w = Math.min(Math.max(mw, w), mxw);
29449 h = Math.min(Math.max(mh, h), mxh);
29452 diffY = this.constrain(h, diffY, mh, mxh);
29459 var adiffX = Math.abs(diffX);
29460 var sub = (adiffX % wi); // how much
29461 if (sub > (wi/2)) { // far enough to snap
29462 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29464 // remove difference..
29465 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29469 x = Math.max(this.minX, x);
29472 diffX = this.constrain(w, diffX, mw, mxw);
29478 w = Math.min(Math.max(mw, w), mxw);
29479 diffY = this.constrain(h, diffY, mh, mxh);
29484 diffX = this.constrain(w, diffX, mw, mxw);
29485 diffY = this.constrain(h, diffY, mh, mxh);
29492 diffX = this.constrain(w, diffX, mw, mxw);
29494 h = Math.min(Math.max(mh, h), mxh);
29500 var sw = this.snap(w, wi, mw);
29501 var sh = this.snap(h, hi, mh);
29502 if(sw != w || sh != h){
29525 if(this.preserveRatio){
29530 h = Math.min(Math.max(mh, h), mxh);
29535 w = Math.min(Math.max(mw, w), mxw);
29540 w = Math.min(Math.max(mw, w), mxw);
29546 w = Math.min(Math.max(mw, w), mxw);
29552 h = Math.min(Math.max(mh, h), mxh);
29560 h = Math.min(Math.max(mh, h), mxh);
29570 h = Math.min(Math.max(mh, h), mxh);
29578 if (pos == 'hdrag') {
29581 this.proxy.setBounds(x, y, w, h);
29583 this.resizeElement();
29587 this.fireEvent("resizing", this, x, y, w, h, e);
29591 handleOver : function(){
29593 this.el.addClass("x-resizable-over");
29598 handleOut : function(){
29599 if(!this.resizing){
29600 this.el.removeClass("x-resizable-over");
29605 * Returns the element this component is bound to.
29606 * @return {Roo.Element}
29608 getEl : function(){
29613 * Returns the resizeChild element (or null).
29614 * @return {Roo.Element}
29616 getResizeChild : function(){
29617 return this.resizeChild;
29619 groupHandler : function()
29624 * Destroys this resizable. If the element was wrapped and
29625 * removeEl is not true then the element remains.
29626 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29628 destroy : function(removeEl){
29629 this.proxy.remove();
29631 this.overlay.removeAllListeners();
29632 this.overlay.remove();
29634 var ps = Roo.Resizable.positions;
29636 if(typeof ps[k] != "function" && this[ps[k]]){
29637 var h = this[ps[k]];
29638 h.el.removeAllListeners();
29643 this.el.update("");
29650 // hash to map config positions to true positions
29651 Roo.Resizable.positions = {
29652 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29657 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29659 // only initialize the template if resizable is used
29660 var tpl = Roo.DomHelper.createTemplate(
29661 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29664 Roo.Resizable.Handle.prototype.tpl = tpl;
29666 this.position = pos;
29668 // show north drag fro topdra
29669 var handlepos = pos == 'hdrag' ? 'north' : pos;
29671 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29672 if (pos == 'hdrag') {
29673 this.el.setStyle('cursor', 'pointer');
29675 this.el.unselectable();
29677 this.el.setOpacity(0);
29679 this.el.on("mousedown", this.onMouseDown, this);
29680 if(!disableTrackOver){
29681 this.el.on("mouseover", this.onMouseOver, this);
29682 this.el.on("mouseout", this.onMouseOut, this);
29687 Roo.Resizable.Handle.prototype = {
29688 afterResize : function(rz){
29693 onMouseDown : function(e){
29694 this.rz.onMouseDown(this, e);
29697 onMouseOver : function(e){
29698 this.rz.handleOver(this, e);
29701 onMouseOut : function(e){
29702 this.rz.handleOut(this, e);
29706 * Ext JS Library 1.1.1
29707 * Copyright(c) 2006-2007, Ext JS, LLC.
29709 * Originally Released Under LGPL - original licence link has changed is not relivant.
29712 * <script type="text/javascript">
29716 * @class Roo.Editor
29717 * @extends Roo.Component
29718 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29720 * Create a new Editor
29721 * @param {Roo.form.Field} field The Field object (or descendant)
29722 * @param {Object} config The config object
29724 Roo.Editor = function(field, config){
29725 Roo.Editor.superclass.constructor.call(this, config);
29726 this.field = field;
29729 * @event beforestartedit
29730 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29731 * false from the handler of this event.
29732 * @param {Editor} this
29733 * @param {Roo.Element} boundEl The underlying element bound to this editor
29734 * @param {Mixed} value The field value being set
29736 "beforestartedit" : true,
29739 * Fires when this editor is displayed
29740 * @param {Roo.Element} boundEl The underlying element bound to this editor
29741 * @param {Mixed} value The starting field value
29743 "startedit" : true,
29745 * @event beforecomplete
29746 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29747 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29748 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29749 * event will not fire since no edit actually occurred.
29750 * @param {Editor} this
29751 * @param {Mixed} value The current field value
29752 * @param {Mixed} startValue The original field value
29754 "beforecomplete" : true,
29757 * Fires after editing is complete and any changed value has been written to the underlying field.
29758 * @param {Editor} this
29759 * @param {Mixed} value The current field value
29760 * @param {Mixed} startValue The original field value
29764 * @event specialkey
29765 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29766 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29767 * @param {Roo.form.Field} this
29768 * @param {Roo.EventObject} e The event object
29770 "specialkey" : true
29774 Roo.extend(Roo.Editor, Roo.Component, {
29776 * @cfg {Boolean/String} autosize
29777 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29778 * or "height" to adopt the height only (defaults to false)
29781 * @cfg {Boolean} revertInvalid
29782 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29783 * validation fails (defaults to true)
29786 * @cfg {Boolean} ignoreNoChange
29787 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29788 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29789 * will never be ignored.
29792 * @cfg {Boolean} hideEl
29793 * False to keep the bound element visible while the editor is displayed (defaults to true)
29796 * @cfg {Mixed} value
29797 * The data value of the underlying field (defaults to "")
29801 * @cfg {String} alignment
29802 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29806 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29807 * for bottom-right shadow (defaults to "frame")
29811 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29815 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29817 completeOnEnter : false,
29819 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29821 cancelOnEsc : false,
29823 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29828 onRender : function(ct, position){
29829 this.el = new Roo.Layer({
29830 shadow: this.shadow,
29836 constrain: this.constrain
29838 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29839 if(this.field.msgTarget != 'title'){
29840 this.field.msgTarget = 'qtip';
29842 this.field.render(this.el);
29844 this.field.el.dom.setAttribute('autocomplete', 'off');
29846 this.field.on("specialkey", this.onSpecialKey, this);
29847 if(this.swallowKeys){
29848 this.field.el.swallowEvent(['keydown','keypress']);
29851 this.field.on("blur", this.onBlur, this);
29852 if(this.field.grow){
29853 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29857 onSpecialKey : function(field, e)
29859 //Roo.log('editor onSpecialKey');
29860 if(this.completeOnEnter && e.getKey() == e.ENTER){
29862 this.completeEdit();
29865 // do not fire special key otherwise it might hide close the editor...
29866 if(e.getKey() == e.ENTER){
29869 if(this.cancelOnEsc && e.getKey() == e.ESC){
29873 this.fireEvent('specialkey', field, e);
29878 * Starts the editing process and shows the editor.
29879 * @param {String/HTMLElement/Element} el The element to edit
29880 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29881 * to the innerHTML of el.
29883 startEdit : function(el, value){
29885 this.completeEdit();
29887 this.boundEl = Roo.get(el);
29888 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29889 if(!this.rendered){
29890 this.render(this.parentEl || document.body);
29892 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29895 this.startValue = v;
29896 this.field.setValue(v);
29898 var sz = this.boundEl.getSize();
29899 switch(this.autoSize){
29901 this.setSize(sz.width, "");
29904 this.setSize("", sz.height);
29907 this.setSize(sz.width, sz.height);
29910 this.el.alignTo(this.boundEl, this.alignment);
29911 this.editing = true;
29913 Roo.QuickTips.disable();
29919 * Sets the height and width of this editor.
29920 * @param {Number} width The new width
29921 * @param {Number} height The new height
29923 setSize : function(w, h){
29924 this.field.setSize(w, h);
29931 * Realigns the editor to the bound field based on the current alignment config value.
29933 realign : function(){
29934 this.el.alignTo(this.boundEl, this.alignment);
29938 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29939 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29941 completeEdit : function(remainVisible){
29945 var v = this.getValue();
29946 if(this.revertInvalid !== false && !this.field.isValid()){
29947 v = this.startValue;
29948 this.cancelEdit(true);
29950 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29951 this.editing = false;
29955 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29956 this.editing = false;
29957 if(this.updateEl && this.boundEl){
29958 this.boundEl.update(v);
29960 if(remainVisible !== true){
29963 this.fireEvent("complete", this, v, this.startValue);
29968 onShow : function(){
29970 if(this.hideEl !== false){
29971 this.boundEl.hide();
29974 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29975 this.fixIEFocus = true;
29976 this.deferredFocus.defer(50, this);
29978 this.field.focus();
29980 this.fireEvent("startedit", this.boundEl, this.startValue);
29983 deferredFocus : function(){
29985 this.field.focus();
29990 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29991 * reverted to the original starting value.
29992 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29993 * cancel (defaults to false)
29995 cancelEdit : function(remainVisible){
29997 this.setValue(this.startValue);
29998 if(remainVisible !== true){
30005 onBlur : function(){
30006 if(this.allowBlur !== true && this.editing){
30007 this.completeEdit();
30012 onHide : function(){
30014 this.completeEdit();
30018 if(this.field.collapse){
30019 this.field.collapse();
30022 if(this.hideEl !== false){
30023 this.boundEl.show();
30026 Roo.QuickTips.enable();
30031 * Sets the data value of the editor
30032 * @param {Mixed} value Any valid value supported by the underlying field
30034 setValue : function(v){
30035 this.field.setValue(v);
30039 * Gets the data value of the editor
30040 * @return {Mixed} The data value
30042 getValue : function(){
30043 return this.field.getValue();
30047 * Ext JS Library 1.1.1
30048 * Copyright(c) 2006-2007, Ext JS, LLC.
30050 * Originally Released Under LGPL - original licence link has changed is not relivant.
30053 * <script type="text/javascript">
30057 * @class Roo.BasicDialog
30058 * @extends Roo.util.Observable
30059 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30061 var dlg = new Roo.BasicDialog("my-dlg", {
30070 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30071 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30072 dlg.addButton('Cancel', dlg.hide, dlg);
30075 <b>A Dialog should always be a direct child of the body element.</b>
30076 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30077 * @cfg {String} title Default text to display in the title bar (defaults to null)
30078 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30079 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30080 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30081 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30082 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30083 * (defaults to null with no animation)
30084 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30085 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30086 * property for valid values (defaults to 'all')
30087 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30088 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30089 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30090 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30091 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30092 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30093 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30094 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30095 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30096 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30097 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30098 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30099 * draggable = true (defaults to false)
30100 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30101 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30102 * shadow (defaults to false)
30103 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30104 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30105 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30106 * @cfg {Array} buttons Array of buttons
30107 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30109 * Create a new BasicDialog.
30110 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30111 * @param {Object} config Configuration options
30113 Roo.BasicDialog = function(el, config){
30114 this.el = Roo.get(el);
30115 var dh = Roo.DomHelper;
30116 if(!this.el && config && config.autoCreate){
30117 if(typeof config.autoCreate == "object"){
30118 if(!config.autoCreate.id){
30119 config.autoCreate.id = el;
30121 this.el = dh.append(document.body,
30122 config.autoCreate, true);
30124 this.el = dh.append(document.body,
30125 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30129 el.setDisplayed(true);
30130 el.hide = this.hideAction;
30132 el.addClass("x-dlg");
30134 Roo.apply(this, config);
30136 this.proxy = el.createProxy("x-dlg-proxy");
30137 this.proxy.hide = this.hideAction;
30138 this.proxy.setOpacity(.5);
30142 el.setWidth(config.width);
30145 el.setHeight(config.height);
30147 this.size = el.getSize();
30148 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30149 this.xy = [config.x,config.y];
30151 this.xy = el.getCenterXY(true);
30153 /** The header element @type Roo.Element */
30154 this.header = el.child("> .x-dlg-hd");
30155 /** The body element @type Roo.Element */
30156 this.body = el.child("> .x-dlg-bd");
30157 /** The footer element @type Roo.Element */
30158 this.footer = el.child("> .x-dlg-ft");
30161 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30164 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30167 this.header.unselectable();
30169 this.header.update(this.title);
30171 // this element allows the dialog to be focused for keyboard event
30172 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30173 this.focusEl.swallowEvent("click", true);
30175 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30177 // wrap the body and footer for special rendering
30178 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30180 this.bwrap.dom.appendChild(this.footer.dom);
30183 this.bg = this.el.createChild({
30184 tag: "div", cls:"x-dlg-bg",
30185 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30187 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30190 if(this.autoScroll !== false && !this.autoTabs){
30191 this.body.setStyle("overflow", "auto");
30194 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30196 if(this.closable !== false){
30197 this.el.addClass("x-dlg-closable");
30198 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30199 this.close.on("click", this.closeClick, this);
30200 this.close.addClassOnOver("x-dlg-close-over");
30202 if(this.collapsible !== false){
30203 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30204 this.collapseBtn.on("click", this.collapseClick, this);
30205 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30206 this.header.on("dblclick", this.collapseClick, this);
30208 if(this.resizable !== false){
30209 this.el.addClass("x-dlg-resizable");
30210 this.resizer = new Roo.Resizable(el, {
30211 minWidth: this.minWidth || 80,
30212 minHeight:this.minHeight || 80,
30213 handles: this.resizeHandles || "all",
30216 this.resizer.on("beforeresize", this.beforeResize, this);
30217 this.resizer.on("resize", this.onResize, this);
30219 if(this.draggable !== false){
30220 el.addClass("x-dlg-draggable");
30221 if (!this.proxyDrag) {
30222 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30225 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30227 dd.setHandleElId(this.header.id);
30228 dd.endDrag = this.endMove.createDelegate(this);
30229 dd.startDrag = this.startMove.createDelegate(this);
30230 dd.onDrag = this.onDrag.createDelegate(this);
30235 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30236 this.mask.enableDisplayMode("block");
30238 this.el.addClass("x-dlg-modal");
30241 this.shadow = new Roo.Shadow({
30242 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30243 offset : this.shadowOffset
30246 this.shadowOffset = 0;
30248 if(Roo.useShims && this.shim !== false){
30249 this.shim = this.el.createShim();
30250 this.shim.hide = this.hideAction;
30258 if (this.buttons) {
30259 var bts= this.buttons;
30261 Roo.each(bts, function(b) {
30270 * Fires when a key is pressed
30271 * @param {Roo.BasicDialog} this
30272 * @param {Roo.EventObject} e
30277 * Fires when this dialog is moved by the user.
30278 * @param {Roo.BasicDialog} this
30279 * @param {Number} x The new page X
30280 * @param {Number} y The new page Y
30285 * Fires when this dialog is resized by the user.
30286 * @param {Roo.BasicDialog} this
30287 * @param {Number} width The new width
30288 * @param {Number} height The new height
30292 * @event beforehide
30293 * Fires before this dialog is hidden.
30294 * @param {Roo.BasicDialog} this
30296 "beforehide" : true,
30299 * Fires when this dialog is hidden.
30300 * @param {Roo.BasicDialog} this
30304 * @event beforeshow
30305 * Fires before this dialog is shown.
30306 * @param {Roo.BasicDialog} this
30308 "beforeshow" : true,
30311 * Fires when this dialog is shown.
30312 * @param {Roo.BasicDialog} this
30316 el.on("keydown", this.onKeyDown, this);
30317 el.on("mousedown", this.toFront, this);
30318 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30320 Roo.DialogManager.register(this);
30321 Roo.BasicDialog.superclass.constructor.call(this);
30324 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30325 shadowOffset: Roo.isIE ? 6 : 5,
30328 minButtonWidth: 75,
30329 defaultButton: null,
30330 buttonAlign: "right",
30335 * Sets the dialog title text
30336 * @param {String} text The title text to display
30337 * @return {Roo.BasicDialog} this
30339 setTitle : function(text){
30340 this.header.update(text);
30345 closeClick : function(){
30350 collapseClick : function(){
30351 this[this.collapsed ? "expand" : "collapse"]();
30355 * Collapses the dialog to its minimized state (only the title bar is visible).
30356 * Equivalent to the user clicking the collapse dialog button.
30358 collapse : function(){
30359 if(!this.collapsed){
30360 this.collapsed = true;
30361 this.el.addClass("x-dlg-collapsed");
30362 this.restoreHeight = this.el.getHeight();
30363 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30368 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30369 * clicking the expand dialog button.
30371 expand : function(){
30372 if(this.collapsed){
30373 this.collapsed = false;
30374 this.el.removeClass("x-dlg-collapsed");
30375 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30380 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30381 * @return {Roo.TabPanel} The tabs component
30383 initTabs : function(){
30384 var tabs = this.getTabs();
30385 while(tabs.getTab(0)){
30388 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30390 tabs.addTab(Roo.id(dom), dom.title);
30398 beforeResize : function(){
30399 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30403 onResize : function(){
30404 this.refreshSize();
30405 this.syncBodyHeight();
30406 this.adjustAssets();
30408 this.fireEvent("resize", this, this.size.width, this.size.height);
30412 onKeyDown : function(e){
30413 if(this.isVisible()){
30414 this.fireEvent("keydown", this, e);
30419 * Resizes the dialog.
30420 * @param {Number} width
30421 * @param {Number} height
30422 * @return {Roo.BasicDialog} this
30424 resizeTo : function(width, height){
30425 this.el.setSize(width, height);
30426 this.size = {width: width, height: height};
30427 this.syncBodyHeight();
30428 if(this.fixedcenter){
30431 if(this.isVisible()){
30432 this.constrainXY();
30433 this.adjustAssets();
30435 this.fireEvent("resize", this, width, height);
30441 * Resizes the dialog to fit the specified content size.
30442 * @param {Number} width
30443 * @param {Number} height
30444 * @return {Roo.BasicDialog} this
30446 setContentSize : function(w, h){
30447 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30448 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30449 //if(!this.el.isBorderBox()){
30450 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30451 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30454 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30455 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30457 this.resizeTo(w, h);
30462 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30463 * executed in response to a particular key being pressed while the dialog is active.
30464 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30465 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30466 * @param {Function} fn The function to call
30467 * @param {Object} scope (optional) The scope of the function
30468 * @return {Roo.BasicDialog} this
30470 addKeyListener : function(key, fn, scope){
30471 var keyCode, shift, ctrl, alt;
30472 if(typeof key == "object" && !(key instanceof Array)){
30473 keyCode = key["key"];
30474 shift = key["shift"];
30475 ctrl = key["ctrl"];
30480 var handler = function(dlg, e){
30481 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30482 var k = e.getKey();
30483 if(keyCode instanceof Array){
30484 for(var i = 0, len = keyCode.length; i < len; i++){
30485 if(keyCode[i] == k){
30486 fn.call(scope || window, dlg, k, e);
30492 fn.call(scope || window, dlg, k, e);
30497 this.on("keydown", handler);
30502 * Returns the TabPanel component (creates it if it doesn't exist).
30503 * Note: If you wish to simply check for the existence of tabs without creating them,
30504 * check for a null 'tabs' property.
30505 * @return {Roo.TabPanel} The tabs component
30507 getTabs : function(){
30509 this.el.addClass("x-dlg-auto-tabs");
30510 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30511 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30517 * Adds a button to the footer section of the dialog.
30518 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30519 * object or a valid Roo.DomHelper element config
30520 * @param {Function} handler The function called when the button is clicked
30521 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30522 * @return {Roo.Button} The new button
30524 addButton : function(config, handler, scope){
30525 var dh = Roo.DomHelper;
30527 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30529 if(!this.btnContainer){
30530 var tb = this.footer.createChild({
30532 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30533 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30535 this.btnContainer = tb.firstChild.firstChild.firstChild;
30540 minWidth: this.minButtonWidth,
30543 if(typeof config == "string"){
30544 bconfig.text = config;
30547 bconfig.dhconfig = config;
30549 Roo.apply(bconfig, config);
30553 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30554 bconfig.position = Math.max(0, bconfig.position);
30555 fc = this.btnContainer.childNodes[bconfig.position];
30558 var btn = new Roo.Button(
30560 this.btnContainer.insertBefore(document.createElement("td"),fc)
30561 : this.btnContainer.appendChild(document.createElement("td")),
30562 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30565 this.syncBodyHeight();
30568 * Array of all the buttons that have been added to this dialog via addButton
30573 this.buttons.push(btn);
30578 * Sets the default button to be focused when the dialog is displayed.
30579 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30580 * @return {Roo.BasicDialog} this
30582 setDefaultButton : function(btn){
30583 this.defaultButton = btn;
30588 getHeaderFooterHeight : function(safe){
30591 height += this.header.getHeight();
30594 var fm = this.footer.getMargins();
30595 height += (this.footer.getHeight()+fm.top+fm.bottom);
30597 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30598 height += this.centerBg.getPadding("tb");
30603 syncBodyHeight : function()
30605 var bd = this.body, // the text
30606 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30608 var height = this.size.height - this.getHeaderFooterHeight(false);
30609 bd.setHeight(height-bd.getMargins("tb"));
30610 var hh = this.header.getHeight();
30611 var h = this.size.height-hh;
30614 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30615 bw.setHeight(h-cb.getPadding("tb"));
30617 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30618 bd.setWidth(bw.getWidth(true));
30620 this.tabs.syncHeight();
30622 this.tabs.el.repaint();
30628 * Restores the previous state of the dialog if Roo.state is configured.
30629 * @return {Roo.BasicDialog} this
30631 restoreState : function(){
30632 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30633 if(box && box.width){
30634 this.xy = [box.x, box.y];
30635 this.resizeTo(box.width, box.height);
30641 beforeShow : function(){
30643 if(this.fixedcenter){
30644 this.xy = this.el.getCenterXY(true);
30647 Roo.get(document.body).addClass("x-body-masked");
30648 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30651 this.constrainXY();
30655 animShow : function(){
30656 var b = Roo.get(this.animateTarget).getBox();
30657 this.proxy.setSize(b.width, b.height);
30658 this.proxy.setLocation(b.x, b.y);
30660 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30661 true, .35, this.showEl.createDelegate(this));
30665 * Shows the dialog.
30666 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30667 * @return {Roo.BasicDialog} this
30669 show : function(animateTarget){
30670 if (this.fireEvent("beforeshow", this) === false){
30673 if(this.syncHeightBeforeShow){
30674 this.syncBodyHeight();
30675 }else if(this.firstShow){
30676 this.firstShow = false;
30677 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30679 this.animateTarget = animateTarget || this.animateTarget;
30680 if(!this.el.isVisible()){
30682 if(this.animateTarget && Roo.get(this.animateTarget)){
30692 showEl : function(){
30694 this.el.setXY(this.xy);
30696 this.adjustAssets(true);
30699 // IE peekaboo bug - fix found by Dave Fenwick
30703 this.fireEvent("show", this);
30707 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30708 * dialog itself will receive focus.
30710 focus : function(){
30711 if(this.defaultButton){
30712 this.defaultButton.focus();
30714 this.focusEl.focus();
30719 constrainXY : function(){
30720 if(this.constraintoviewport !== false){
30721 if(!this.viewSize){
30722 if(this.container){
30723 var s = this.container.getSize();
30724 this.viewSize = [s.width, s.height];
30726 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30729 var s = Roo.get(this.container||document).getScroll();
30731 var x = this.xy[0], y = this.xy[1];
30732 var w = this.size.width, h = this.size.height;
30733 var vw = this.viewSize[0], vh = this.viewSize[1];
30734 // only move it if it needs it
30736 // first validate right/bottom
30737 if(x + w > vw+s.left){
30741 if(y + h > vh+s.top){
30745 // then make sure top/left isn't negative
30757 if(this.isVisible()){
30758 this.el.setLocation(x, y);
30759 this.adjustAssets();
30766 onDrag : function(){
30767 if(!this.proxyDrag){
30768 this.xy = this.el.getXY();
30769 this.adjustAssets();
30774 adjustAssets : function(doShow){
30775 var x = this.xy[0], y = this.xy[1];
30776 var w = this.size.width, h = this.size.height;
30777 if(doShow === true){
30779 this.shadow.show(this.el);
30785 if(this.shadow && this.shadow.isVisible()){
30786 this.shadow.show(this.el);
30788 if(this.shim && this.shim.isVisible()){
30789 this.shim.setBounds(x, y, w, h);
30794 adjustViewport : function(w, h){
30796 w = Roo.lib.Dom.getViewWidth();
30797 h = Roo.lib.Dom.getViewHeight();
30800 this.viewSize = [w, h];
30801 if(this.modal && this.mask.isVisible()){
30802 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30803 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30805 if(this.isVisible()){
30806 this.constrainXY();
30811 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30812 * shadow, proxy, mask, etc.) Also removes all event listeners.
30813 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30815 destroy : function(removeEl){
30816 if(this.isVisible()){
30817 this.animateTarget = null;
30820 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30822 this.tabs.destroy(removeEl);
30835 for(var i = 0, len = this.buttons.length; i < len; i++){
30836 this.buttons[i].destroy();
30839 this.el.removeAllListeners();
30840 if(removeEl === true){
30841 this.el.update("");
30844 Roo.DialogManager.unregister(this);
30848 startMove : function(){
30849 if(this.proxyDrag){
30852 if(this.constraintoviewport !== false){
30853 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30858 endMove : function(){
30859 if(!this.proxyDrag){
30860 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30862 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30865 this.refreshSize();
30866 this.adjustAssets();
30868 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30872 * Brings this dialog to the front of any other visible dialogs
30873 * @return {Roo.BasicDialog} this
30875 toFront : function(){
30876 Roo.DialogManager.bringToFront(this);
30881 * Sends this dialog to the back (under) of any other visible dialogs
30882 * @return {Roo.BasicDialog} this
30884 toBack : function(){
30885 Roo.DialogManager.sendToBack(this);
30890 * Centers this dialog in the viewport
30891 * @return {Roo.BasicDialog} this
30893 center : function(){
30894 var xy = this.el.getCenterXY(true);
30895 this.moveTo(xy[0], xy[1]);
30900 * Moves the dialog's top-left corner to the specified point
30901 * @param {Number} x
30902 * @param {Number} y
30903 * @return {Roo.BasicDialog} this
30905 moveTo : function(x, y){
30907 if(this.isVisible()){
30908 this.el.setXY(this.xy);
30909 this.adjustAssets();
30915 * Aligns the dialog to the specified element
30916 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30917 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30918 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30919 * @return {Roo.BasicDialog} this
30921 alignTo : function(element, position, offsets){
30922 this.xy = this.el.getAlignToXY(element, position, offsets);
30923 if(this.isVisible()){
30924 this.el.setXY(this.xy);
30925 this.adjustAssets();
30931 * Anchors an element to another element and realigns it when the window is resized.
30932 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30933 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30934 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30935 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30936 * is a number, it is used as the buffer delay (defaults to 50ms).
30937 * @return {Roo.BasicDialog} this
30939 anchorTo : function(el, alignment, offsets, monitorScroll){
30940 var action = function(){
30941 this.alignTo(el, alignment, offsets);
30943 Roo.EventManager.onWindowResize(action, this);
30944 var tm = typeof monitorScroll;
30945 if(tm != 'undefined'){
30946 Roo.EventManager.on(window, 'scroll', action, this,
30947 {buffer: tm == 'number' ? monitorScroll : 50});
30954 * Returns true if the dialog is visible
30955 * @return {Boolean}
30957 isVisible : function(){
30958 return this.el.isVisible();
30962 animHide : function(callback){
30963 var b = Roo.get(this.animateTarget).getBox();
30965 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30967 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30968 this.hideEl.createDelegate(this, [callback]));
30972 * Hides the dialog.
30973 * @param {Function} callback (optional) Function to call when the dialog is hidden
30974 * @return {Roo.BasicDialog} this
30976 hide : function(callback){
30977 if (this.fireEvent("beforehide", this) === false){
30981 this.shadow.hide();
30986 // sometimes animateTarget seems to get set.. causing problems...
30987 // this just double checks..
30988 if(this.animateTarget && Roo.get(this.animateTarget)) {
30989 this.animHide(callback);
30992 this.hideEl(callback);
30998 hideEl : function(callback){
31002 Roo.get(document.body).removeClass("x-body-masked");
31004 this.fireEvent("hide", this);
31005 if(typeof callback == "function"){
31011 hideAction : function(){
31012 this.setLeft("-10000px");
31013 this.setTop("-10000px");
31014 this.setStyle("visibility", "hidden");
31018 refreshSize : function(){
31019 this.size = this.el.getSize();
31020 this.xy = this.el.getXY();
31021 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31025 // z-index is managed by the DialogManager and may be overwritten at any time
31026 setZIndex : function(index){
31028 this.mask.setStyle("z-index", index);
31031 this.shim.setStyle("z-index", ++index);
31034 this.shadow.setZIndex(++index);
31036 this.el.setStyle("z-index", ++index);
31038 this.proxy.setStyle("z-index", ++index);
31041 this.resizer.proxy.setStyle("z-index", ++index);
31044 this.lastZIndex = index;
31048 * Returns the element for this dialog
31049 * @return {Roo.Element} The underlying dialog Element
31051 getEl : function(){
31057 * @class Roo.DialogManager
31058 * Provides global access to BasicDialogs that have been created and
31059 * support for z-indexing (layering) multiple open dialogs.
31061 Roo.DialogManager = function(){
31063 var accessList = [];
31067 var sortDialogs = function(d1, d2){
31068 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31072 var orderDialogs = function(){
31073 accessList.sort(sortDialogs);
31074 var seed = Roo.DialogManager.zseed;
31075 for(var i = 0, len = accessList.length; i < len; i++){
31076 var dlg = accessList[i];
31078 dlg.setZIndex(seed + (i*10));
31085 * The starting z-index for BasicDialogs (defaults to 9000)
31086 * @type Number The z-index value
31091 register : function(dlg){
31092 list[dlg.id] = dlg;
31093 accessList.push(dlg);
31097 unregister : function(dlg){
31098 delete list[dlg.id];
31101 if(!accessList.indexOf){
31102 for( i = 0, len = accessList.length; i < len; i++){
31103 if(accessList[i] == dlg){
31104 accessList.splice(i, 1);
31109 i = accessList.indexOf(dlg);
31111 accessList.splice(i, 1);
31117 * Gets a registered dialog by id
31118 * @param {String/Object} id The id of the dialog or a dialog
31119 * @return {Roo.BasicDialog} this
31121 get : function(id){
31122 return typeof id == "object" ? id : list[id];
31126 * Brings the specified dialog to the front
31127 * @param {String/Object} dlg The id of the dialog or a dialog
31128 * @return {Roo.BasicDialog} this
31130 bringToFront : function(dlg){
31131 dlg = this.get(dlg);
31134 dlg._lastAccess = new Date().getTime();
31141 * Sends the specified dialog to the back
31142 * @param {String/Object} dlg The id of the dialog or a dialog
31143 * @return {Roo.BasicDialog} this
31145 sendToBack : function(dlg){
31146 dlg = this.get(dlg);
31147 dlg._lastAccess = -(new Date().getTime());
31153 * Hides all dialogs
31155 hideAll : function(){
31156 for(var id in list){
31157 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31166 * @class Roo.LayoutDialog
31167 * @extends Roo.BasicDialog
31168 * Dialog which provides adjustments for working with a layout in a Dialog.
31169 * Add your necessary layout config options to the dialog's config.<br>
31170 * Example usage (including a nested layout):
31173 dialog = new Roo.LayoutDialog("download-dlg", {
31182 // layout config merges with the dialog config
31184 tabPosition: "top",
31185 alwaysShowTabs: true
31188 dialog.addKeyListener(27, dialog.hide, dialog);
31189 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31190 dialog.addButton("Build It!", this.getDownload, this);
31192 // we can even add nested layouts
31193 var innerLayout = new Roo.BorderLayout("dl-inner", {
31203 innerLayout.beginUpdate();
31204 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31205 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31206 innerLayout.endUpdate(true);
31208 var layout = dialog.getLayout();
31209 layout.beginUpdate();
31210 layout.add("center", new Roo.ContentPanel("standard-panel",
31211 {title: "Download the Source", fitToFrame:true}));
31212 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31213 {title: "Build your own roo.js"}));
31214 layout.getRegion("center").showPanel(sp);
31215 layout.endUpdate();
31219 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31220 * @param {Object} config configuration options
31222 Roo.LayoutDialog = function(el, cfg){
31225 if (typeof(cfg) == 'undefined') {
31226 config = Roo.apply({}, el);
31227 // not sure why we use documentElement here.. - it should always be body.
31228 // IE7 borks horribly if we use documentElement.
31229 // webkit also does not like documentElement - it creates a body element...
31230 el = Roo.get( document.body || document.documentElement ).createChild();
31231 //config.autoCreate = true;
31235 config.autoTabs = false;
31236 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31237 this.body.setStyle({overflow:"hidden", position:"relative"});
31238 this.layout = new Roo.BorderLayout(this.body.dom, config);
31239 this.layout.monitorWindowResize = false;
31240 this.el.addClass("x-dlg-auto-layout");
31241 // fix case when center region overwrites center function
31242 this.center = Roo.BasicDialog.prototype.center;
31243 this.on("show", this.layout.layout, this.layout, true);
31244 if (config.items) {
31245 var xitems = config.items;
31246 delete config.items;
31247 Roo.each(xitems, this.addxtype, this);
31252 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31254 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31257 endUpdate : function(){
31258 this.layout.endUpdate();
31262 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31265 beginUpdate : function(){
31266 this.layout.beginUpdate();
31270 * Get the BorderLayout for this dialog
31271 * @return {Roo.BorderLayout}
31273 getLayout : function(){
31274 return this.layout;
31277 showEl : function(){
31278 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31280 this.layout.layout();
31285 // Use the syncHeightBeforeShow config option to control this automatically
31286 syncBodyHeight : function(){
31287 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31288 if(this.layout){this.layout.layout();}
31292 * Add an xtype element (actually adds to the layout.)
31293 * @return {Object} xdata xtype object data.
31296 addxtype : function(c) {
31297 return this.layout.addxtype(c);
31301 * Ext JS Library 1.1.1
31302 * Copyright(c) 2006-2007, Ext JS, LLC.
31304 * Originally Released Under LGPL - original licence link has changed is not relivant.
31307 * <script type="text/javascript">
31311 * @class Roo.MessageBox
31312 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31316 Roo.Msg.alert('Status', 'Changes saved successfully.');
31318 // Prompt for user data:
31319 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31321 // process text value...
31325 // Show a dialog using config options:
31327 title:'Save Changes?',
31328 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31329 buttons: Roo.Msg.YESNOCANCEL,
31336 Roo.MessageBox = function(){
31337 var dlg, opt, mask, waitTimer;
31338 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31339 var buttons, activeTextEl, bwidth;
31342 var handleButton = function(button){
31344 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31348 var handleHide = function(){
31349 if(opt && opt.cls){
31350 dlg.el.removeClass(opt.cls);
31353 Roo.TaskMgr.stop(waitTimer);
31359 var updateButtons = function(b){
31362 buttons["ok"].hide();
31363 buttons["cancel"].hide();
31364 buttons["yes"].hide();
31365 buttons["no"].hide();
31366 dlg.footer.dom.style.display = 'none';
31369 dlg.footer.dom.style.display = '';
31370 for(var k in buttons){
31371 if(typeof buttons[k] != "function"){
31374 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31375 width += buttons[k].el.getWidth()+15;
31385 var handleEsc = function(d, k, e){
31386 if(opt && opt.closable !== false){
31396 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31397 * @return {Roo.BasicDialog} The BasicDialog element
31399 getDialog : function(){
31401 dlg = new Roo.BasicDialog("x-msg-box", {
31406 constraintoviewport:false,
31408 collapsible : false,
31411 width:400, height:100,
31412 buttonAlign:"center",
31413 closeClick : function(){
31414 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31415 handleButton("no");
31417 handleButton("cancel");
31421 dlg.on("hide", handleHide);
31423 dlg.addKeyListener(27, handleEsc);
31425 var bt = this.buttonText;
31426 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31427 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31428 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31429 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31430 bodyEl = dlg.body.createChild({
31432 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>'
31434 msgEl = bodyEl.dom.firstChild;
31435 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31436 textboxEl.enableDisplayMode();
31437 textboxEl.addKeyListener([10,13], function(){
31438 if(dlg.isVisible() && opt && opt.buttons){
31439 if(opt.buttons.ok){
31440 handleButton("ok");
31441 }else if(opt.buttons.yes){
31442 handleButton("yes");
31446 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31447 textareaEl.enableDisplayMode();
31448 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31449 progressEl.enableDisplayMode();
31450 var pf = progressEl.dom.firstChild;
31452 pp = Roo.get(pf.firstChild);
31453 pp.setHeight(pf.offsetHeight);
31461 * Updates the message box body text
31462 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31463 * the XHTML-compliant non-breaking space character '&#160;')
31464 * @return {Roo.MessageBox} This message box
31466 updateText : function(text){
31467 if(!dlg.isVisible() && !opt.width){
31468 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31470 msgEl.innerHTML = text || ' ';
31472 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31473 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31475 Math.min(opt.width || cw , this.maxWidth),
31476 Math.max(opt.minWidth || this.minWidth, bwidth)
31479 activeTextEl.setWidth(w);
31481 if(dlg.isVisible()){
31482 dlg.fixedcenter = false;
31484 // to big, make it scroll. = But as usual stupid IE does not support
31487 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31488 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31489 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31491 bodyEl.dom.style.height = '';
31492 bodyEl.dom.style.overflowY = '';
31495 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31497 bodyEl.dom.style.overflowX = '';
31500 dlg.setContentSize(w, bodyEl.getHeight());
31501 if(dlg.isVisible()){
31502 dlg.fixedcenter = true;
31508 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31509 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31510 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31511 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31512 * @return {Roo.MessageBox} This message box
31514 updateProgress : function(value, text){
31516 this.updateText(text);
31518 if (pp) { // weird bug on my firefox - for some reason this is not defined
31519 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31525 * Returns true if the message box is currently displayed
31526 * @return {Boolean} True if the message box is visible, else false
31528 isVisible : function(){
31529 return dlg && dlg.isVisible();
31533 * Hides the message box if it is displayed
31536 if(this.isVisible()){
31542 * Displays a new message box, or reinitializes an existing message box, based on the config options
31543 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31544 * The following config object properties are supported:
31546 Property Type Description
31547 ---------- --------------- ------------------------------------------------------------------------------------
31548 animEl String/Element An id or Element from which the message box should animate as it opens and
31549 closes (defaults to undefined)
31550 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31551 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31552 closable Boolean False to hide the top-right close button (defaults to true). Note that
31553 progress and wait dialogs will ignore this property and always hide the
31554 close button as they can only be closed programmatically.
31555 cls String A custom CSS class to apply to the message box element
31556 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31557 displayed (defaults to 75)
31558 fn Function A callback function to execute after closing the dialog. The arguments to the
31559 function will be btn (the name of the button that was clicked, if applicable,
31560 e.g. "ok"), and text (the value of the active text field, if applicable).
31561 Progress and wait dialogs will ignore this option since they do not respond to
31562 user actions and can only be closed programmatically, so any required function
31563 should be called by the same code after it closes the dialog.
31564 icon String A CSS class that provides a background image to be used as an icon for
31565 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31566 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31567 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31568 modal Boolean False to allow user interaction with the page while the message box is
31569 displayed (defaults to true)
31570 msg String A string that will replace the existing message box body text (defaults
31571 to the XHTML-compliant non-breaking space character ' ')
31572 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31573 progress Boolean True to display a progress bar (defaults to false)
31574 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31575 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31576 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31577 title String The title text
31578 value String The string value to set into the active textbox element if displayed
31579 wait Boolean True to display a progress bar (defaults to false)
31580 width Number The width of the dialog in pixels
31587 msg: 'Please enter your address:',
31589 buttons: Roo.MessageBox.OKCANCEL,
31592 animEl: 'addAddressBtn'
31595 * @param {Object} config Configuration options
31596 * @return {Roo.MessageBox} This message box
31598 show : function(options)
31601 // this causes nightmares if you show one dialog after another
31602 // especially on callbacks..
31604 if(this.isVisible()){
31607 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31608 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31609 Roo.log("New Dialog Message:" + options.msg )
31610 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31611 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31614 var d = this.getDialog();
31616 d.setTitle(opt.title || " ");
31617 d.close.setDisplayed(opt.closable !== false);
31618 activeTextEl = textboxEl;
31619 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31624 textareaEl.setHeight(typeof opt.multiline == "number" ?
31625 opt.multiline : this.defaultTextHeight);
31626 activeTextEl = textareaEl;
31635 progressEl.setDisplayed(opt.progress === true);
31636 this.updateProgress(0);
31637 activeTextEl.dom.value = opt.value || "";
31639 dlg.setDefaultButton(activeTextEl);
31641 var bs = opt.buttons;
31644 db = buttons["ok"];
31645 }else if(bs && bs.yes){
31646 db = buttons["yes"];
31648 dlg.setDefaultButton(db);
31650 bwidth = updateButtons(opt.buttons);
31651 this.updateText(opt.msg);
31653 d.el.addClass(opt.cls);
31655 d.proxyDrag = opt.proxyDrag === true;
31656 d.modal = opt.modal !== false;
31657 d.mask = opt.modal !== false ? mask : false;
31658 if(!d.isVisible()){
31659 // force it to the end of the z-index stack so it gets a cursor in FF
31660 document.body.appendChild(dlg.el.dom);
31661 d.animateTarget = null;
31662 d.show(options.animEl);
31668 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31669 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31670 * and closing the message box when the process is complete.
31671 * @param {String} title The title bar text
31672 * @param {String} msg The message box body text
31673 * @return {Roo.MessageBox} This message box
31675 progress : function(title, msg){
31682 minWidth: this.minProgressWidth,
31689 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31690 * If a callback function is passed it will be called after the user clicks the button, and the
31691 * id of the button that was clicked will be passed as the only parameter to the callback
31692 * (could also be the top-right close button).
31693 * @param {String} title The title bar text
31694 * @param {String} msg The message box body text
31695 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31696 * @param {Object} scope (optional) The scope of the callback function
31697 * @return {Roo.MessageBox} This message box
31699 alert : function(title, msg, fn, scope){
31712 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31713 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31714 * You are responsible for closing the message box when the process is complete.
31715 * @param {String} msg The message box body text
31716 * @param {String} title (optional) The title bar text
31717 * @return {Roo.MessageBox} This message box
31719 wait : function(msg, title){
31730 waitTimer = Roo.TaskMgr.start({
31732 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31740 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31741 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31742 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31743 * @param {String} title The title bar text
31744 * @param {String} msg The message box body text
31745 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31746 * @param {Object} scope (optional) The scope of the callback function
31747 * @return {Roo.MessageBox} This message box
31749 confirm : function(title, msg, fn, scope){
31753 buttons: this.YESNO,
31762 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31763 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31764 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31765 * (could also be the top-right close button) and the text that was entered will be passed as the two
31766 * parameters to the callback.
31767 * @param {String} title The title bar text
31768 * @param {String} msg The message box body text
31769 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31770 * @param {Object} scope (optional) The scope of the callback function
31771 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31772 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31773 * @return {Roo.MessageBox} This message box
31775 prompt : function(title, msg, fn, scope, multiline){
31779 buttons: this.OKCANCEL,
31784 multiline: multiline,
31791 * Button config that displays a single OK button
31796 * Button config that displays Yes and No buttons
31799 YESNO : {yes:true, no:true},
31801 * Button config that displays OK and Cancel buttons
31804 OKCANCEL : {ok:true, cancel:true},
31806 * Button config that displays Yes, No and Cancel buttons
31809 YESNOCANCEL : {yes:true, no:true, cancel:true},
31812 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31815 defaultTextHeight : 75,
31817 * The maximum width in pixels of the message box (defaults to 600)
31822 * The minimum width in pixels of the message box (defaults to 100)
31827 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31828 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31831 minProgressWidth : 250,
31833 * An object containing the default button text strings that can be overriden for localized language support.
31834 * Supported properties are: ok, cancel, yes and no.
31835 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31848 * Shorthand for {@link Roo.MessageBox}
31850 Roo.Msg = Roo.MessageBox;/*
31852 * Ext JS Library 1.1.1
31853 * Copyright(c) 2006-2007, Ext JS, LLC.
31855 * Originally Released Under LGPL - original licence link has changed is not relivant.
31858 * <script type="text/javascript">
31861 * @class Roo.QuickTips
31862 * Provides attractive and customizable tooltips for any element.
31865 Roo.QuickTips = function(){
31866 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31867 var ce, bd, xy, dd;
31868 var visible = false, disabled = true, inited = false;
31869 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31871 var onOver = function(e){
31875 var t = e.getTarget();
31876 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31879 if(ce && t == ce.el){
31880 clearTimeout(hideProc);
31883 if(t && tagEls[t.id]){
31884 tagEls[t.id].el = t;
31885 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31888 var ttp, et = Roo.fly(t);
31889 var ns = cfg.namespace;
31890 if(tm.interceptTitles && t.title){
31893 t.removeAttribute("title");
31894 e.preventDefault();
31896 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31899 showProc = show.defer(tm.showDelay, tm, [{
31902 width: et.getAttributeNS(ns, cfg.width),
31903 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31904 title: et.getAttributeNS(ns, cfg.title),
31905 cls: et.getAttributeNS(ns, cfg.cls)
31910 var onOut = function(e){
31911 clearTimeout(showProc);
31912 var t = e.getTarget();
31913 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31914 hideProc = setTimeout(hide, tm.hideDelay);
31918 var onMove = function(e){
31924 if(tm.trackMouse && ce){
31929 var onDown = function(e){
31930 clearTimeout(showProc);
31931 clearTimeout(hideProc);
31933 if(tm.hideOnClick){
31936 tm.enable.defer(100, tm);
31941 var getPad = function(){
31942 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31945 var show = function(o){
31949 clearTimeout(dismissProc);
31951 if(removeCls){ // in case manually hidden
31952 el.removeClass(removeCls);
31956 el.addClass(ce.cls);
31957 removeCls = ce.cls;
31960 tipTitle.update(ce.title);
31963 tipTitle.update('');
31966 el.dom.style.width = tm.maxWidth+'px';
31967 //tipBody.dom.style.width = '';
31968 tipBodyText.update(o.text);
31969 var p = getPad(), w = ce.width;
31971 var td = tipBodyText.dom;
31972 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31973 if(aw > tm.maxWidth){
31975 }else if(aw < tm.minWidth){
31981 //tipBody.setWidth(w);
31982 el.setWidth(parseInt(w, 10) + p);
31983 if(ce.autoHide === false){
31984 close.setDisplayed(true);
31989 close.setDisplayed(false);
31995 el.avoidY = xy[1]-18;
32000 el.setStyle("visibility", "visible");
32001 el.fadeIn({callback: afterShow});
32007 var afterShow = function(){
32011 if(tm.autoDismiss && ce.autoHide !== false){
32012 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32017 var hide = function(noanim){
32018 clearTimeout(dismissProc);
32019 clearTimeout(hideProc);
32021 if(el.isVisible()){
32023 if(noanim !== true && tm.animate){
32024 el.fadeOut({callback: afterHide});
32031 var afterHide = function(){
32034 el.removeClass(removeCls);
32041 * @cfg {Number} minWidth
32042 * The minimum width of the quick tip (defaults to 40)
32046 * @cfg {Number} maxWidth
32047 * The maximum width of the quick tip (defaults to 300)
32051 * @cfg {Boolean} interceptTitles
32052 * True to automatically use the element's DOM title value if available (defaults to false)
32054 interceptTitles : false,
32056 * @cfg {Boolean} trackMouse
32057 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32059 trackMouse : false,
32061 * @cfg {Boolean} hideOnClick
32062 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32064 hideOnClick : true,
32066 * @cfg {Number} showDelay
32067 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32071 * @cfg {Number} hideDelay
32072 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32076 * @cfg {Boolean} autoHide
32077 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32078 * Used in conjunction with hideDelay.
32083 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32084 * (defaults to true). Used in conjunction with autoDismissDelay.
32086 autoDismiss : true,
32089 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32091 autoDismissDelay : 5000,
32093 * @cfg {Boolean} animate
32094 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32099 * @cfg {String} title
32100 * Title text to display (defaults to ''). This can be any valid HTML markup.
32104 * @cfg {String} text
32105 * Body text to display (defaults to ''). This can be any valid HTML markup.
32109 * @cfg {String} cls
32110 * A CSS class to apply to the base quick tip element (defaults to '').
32114 * @cfg {Number} width
32115 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32116 * minWidth or maxWidth.
32121 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32122 * or display QuickTips in a page.
32125 tm = Roo.QuickTips;
32126 cfg = tm.tagConfig;
32128 if(!Roo.isReady){ // allow calling of init() before onReady
32129 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32132 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32133 el.fxDefaults = {stopFx: true};
32134 // maximum custom styling
32135 //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>');
32136 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>');
32137 tipTitle = el.child('h3');
32138 tipTitle.enableDisplayMode("block");
32139 tipBody = el.child('div.x-tip-bd');
32140 tipBodyText = el.child('div.x-tip-bd-inner');
32141 //bdLeft = el.child('div.x-tip-bd-left');
32142 //bdRight = el.child('div.x-tip-bd-right');
32143 close = el.child('div.x-tip-close');
32144 close.enableDisplayMode("block");
32145 close.on("click", hide);
32146 var d = Roo.get(document);
32147 d.on("mousedown", onDown);
32148 d.on("mouseover", onOver);
32149 d.on("mouseout", onOut);
32150 d.on("mousemove", onMove);
32151 esc = d.addKeyListener(27, hide);
32154 dd = el.initDD("default", null, {
32155 onDrag : function(){
32159 dd.setHandleElId(tipTitle.id);
32168 * Configures a new quick tip instance and assigns it to a target element. The following config options
32171 Property Type Description
32172 ---------- --------------------- ------------------------------------------------------------------------
32173 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32175 * @param {Object} config The config object
32177 register : function(config){
32178 var cs = config instanceof Array ? config : arguments;
32179 for(var i = 0, len = cs.length; i < len; i++) {
32181 var target = c.target;
32183 if(target instanceof Array){
32184 for(var j = 0, jlen = target.length; j < jlen; j++){
32185 tagEls[target[j]] = c;
32188 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32195 * Removes this quick tip from its element and destroys it.
32196 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32198 unregister : function(el){
32199 delete tagEls[Roo.id(el)];
32203 * Enable this quick tip.
32205 enable : function(){
32206 if(inited && disabled){
32208 if(locks.length < 1){
32215 * Disable this quick tip.
32217 disable : function(){
32219 clearTimeout(showProc);
32220 clearTimeout(hideProc);
32221 clearTimeout(dismissProc);
32229 * Returns true if the quick tip is enabled, else false.
32231 isEnabled : function(){
32238 attribute : "qtip",
32248 // backwards compat
32249 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32251 * Ext JS Library 1.1.1
32252 * Copyright(c) 2006-2007, Ext JS, LLC.
32254 * Originally Released Under LGPL - original licence link has changed is not relivant.
32257 * <script type="text/javascript">
32262 * @class Roo.tree.TreePanel
32263 * @extends Roo.data.Tree
32265 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32266 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32267 * @cfg {Boolean} enableDD true to enable drag and drop
32268 * @cfg {Boolean} enableDrag true to enable just drag
32269 * @cfg {Boolean} enableDrop true to enable just drop
32270 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32271 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32272 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32273 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32274 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32275 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32276 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32277 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32278 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32279 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32280 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32281 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32282 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32283 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32284 * @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>
32285 * @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>
32288 * @param {String/HTMLElement/Element} el The container element
32289 * @param {Object} config
32291 Roo.tree.TreePanel = function(el, config){
32293 var loader = false;
32295 root = config.root;
32296 delete config.root;
32298 if (config.loader) {
32299 loader = config.loader;
32300 delete config.loader;
32303 Roo.apply(this, config);
32304 Roo.tree.TreePanel.superclass.constructor.call(this);
32305 this.el = Roo.get(el);
32306 this.el.addClass('x-tree');
32307 //console.log(root);
32309 this.setRootNode( Roo.factory(root, Roo.tree));
32312 this.loader = Roo.factory(loader, Roo.tree);
32315 * Read-only. The id of the container element becomes this TreePanel's id.
32317 this.id = this.el.id;
32320 * @event beforeload
32321 * Fires before a node is loaded, return false to cancel
32322 * @param {Node} node The node being loaded
32324 "beforeload" : true,
32327 * Fires when a node is loaded
32328 * @param {Node} node The node that was loaded
32332 * @event textchange
32333 * Fires when the text for a node is changed
32334 * @param {Node} node The node
32335 * @param {String} text The new text
32336 * @param {String} oldText The old text
32338 "textchange" : true,
32340 * @event beforeexpand
32341 * Fires before a node is expanded, return false to cancel.
32342 * @param {Node} node The node
32343 * @param {Boolean} deep
32344 * @param {Boolean} anim
32346 "beforeexpand" : true,
32348 * @event beforecollapse
32349 * Fires before a node is collapsed, return false to cancel.
32350 * @param {Node} node The node
32351 * @param {Boolean} deep
32352 * @param {Boolean} anim
32354 "beforecollapse" : true,
32357 * Fires when a node is expanded
32358 * @param {Node} node The node
32362 * @event disabledchange
32363 * Fires when the disabled status of a node changes
32364 * @param {Node} node The node
32365 * @param {Boolean} disabled
32367 "disabledchange" : true,
32370 * Fires when a node is collapsed
32371 * @param {Node} node The node
32375 * @event beforeclick
32376 * Fires before click processing on a node. Return false to cancel the default action.
32377 * @param {Node} node The node
32378 * @param {Roo.EventObject} e The event object
32380 "beforeclick":true,
32382 * @event checkchange
32383 * Fires when a node with a checkbox's checked property changes
32384 * @param {Node} this This node
32385 * @param {Boolean} checked
32387 "checkchange":true,
32390 * Fires when a node is clicked
32391 * @param {Node} node The node
32392 * @param {Roo.EventObject} e The event object
32397 * Fires when a node is double clicked
32398 * @param {Node} node The node
32399 * @param {Roo.EventObject} e The event object
32403 * @event contextmenu
32404 * Fires when a node is right clicked
32405 * @param {Node} node The node
32406 * @param {Roo.EventObject} e The event object
32408 "contextmenu":true,
32410 * @event beforechildrenrendered
32411 * Fires right before the child nodes for a node are rendered
32412 * @param {Node} node The node
32414 "beforechildrenrendered":true,
32417 * Fires when a node starts being dragged
32418 * @param {Roo.tree.TreePanel} this
32419 * @param {Roo.tree.TreeNode} node
32420 * @param {event} e The raw browser event
32422 "startdrag" : true,
32425 * Fires when a drag operation is complete
32426 * @param {Roo.tree.TreePanel} this
32427 * @param {Roo.tree.TreeNode} node
32428 * @param {event} e The raw browser event
32433 * Fires when a dragged node is dropped on a valid DD target
32434 * @param {Roo.tree.TreePanel} this
32435 * @param {Roo.tree.TreeNode} node
32436 * @param {DD} dd The dd it was dropped on
32437 * @param {event} e The raw browser event
32441 * @event beforenodedrop
32442 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32443 * passed to handlers has the following properties:<br />
32444 * <ul style="padding:5px;padding-left:16px;">
32445 * <li>tree - The TreePanel</li>
32446 * <li>target - The node being targeted for the drop</li>
32447 * <li>data - The drag data from the drag source</li>
32448 * <li>point - The point of the drop - append, above or below</li>
32449 * <li>source - The drag source</li>
32450 * <li>rawEvent - Raw mouse event</li>
32451 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32452 * to be inserted by setting them on this object.</li>
32453 * <li>cancel - Set this to true to cancel the drop.</li>
32455 * @param {Object} dropEvent
32457 "beforenodedrop" : true,
32460 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32461 * passed to handlers has the following properties:<br />
32462 * <ul style="padding:5px;padding-left:16px;">
32463 * <li>tree - The TreePanel</li>
32464 * <li>target - The node being targeted for the drop</li>
32465 * <li>data - The drag data from the drag source</li>
32466 * <li>point - The point of the drop - append, above or below</li>
32467 * <li>source - The drag source</li>
32468 * <li>rawEvent - Raw mouse event</li>
32469 * <li>dropNode - Dropped node(s).</li>
32471 * @param {Object} dropEvent
32475 * @event nodedragover
32476 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32477 * passed to handlers has the following properties:<br />
32478 * <ul style="padding:5px;padding-left:16px;">
32479 * <li>tree - The TreePanel</li>
32480 * <li>target - The node being targeted for the drop</li>
32481 * <li>data - The drag data from the drag source</li>
32482 * <li>point - The point of the drop - append, above or below</li>
32483 * <li>source - The drag source</li>
32484 * <li>rawEvent - Raw mouse event</li>
32485 * <li>dropNode - Drop node(s) provided by the source.</li>
32486 * <li>cancel - Set this to true to signal drop not allowed.</li>
32488 * @param {Object} dragOverEvent
32490 "nodedragover" : true
32493 if(this.singleExpand){
32494 this.on("beforeexpand", this.restrictExpand, this);
32497 this.editor.tree = this;
32498 this.editor = Roo.factory(this.editor, Roo.tree);
32501 if (this.selModel) {
32502 this.selModel = Roo.factory(this.selModel, Roo.tree);
32506 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32507 rootVisible : true,
32508 animate: Roo.enableFx,
32511 hlDrop : Roo.enableFx,
32515 rendererTip: false,
32517 restrictExpand : function(node){
32518 var p = node.parentNode;
32520 if(p.expandedChild && p.expandedChild.parentNode == p){
32521 p.expandedChild.collapse();
32523 p.expandedChild = node;
32527 // private override
32528 setRootNode : function(node){
32529 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32530 if(!this.rootVisible){
32531 node.ui = new Roo.tree.RootTreeNodeUI(node);
32537 * Returns the container element for this TreePanel
32539 getEl : function(){
32544 * Returns the default TreeLoader for this TreePanel
32546 getLoader : function(){
32547 return this.loader;
32553 expandAll : function(){
32554 this.root.expand(true);
32558 * Collapse all nodes
32560 collapseAll : function(){
32561 this.root.collapse(true);
32565 * Returns the selection model used by this TreePanel
32567 getSelectionModel : function(){
32568 if(!this.selModel){
32569 this.selModel = new Roo.tree.DefaultSelectionModel();
32571 return this.selModel;
32575 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32576 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32577 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32580 getChecked : function(a, startNode){
32581 startNode = startNode || this.root;
32583 var f = function(){
32584 if(this.attributes.checked){
32585 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32588 startNode.cascade(f);
32593 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32594 * @param {String} path
32595 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32596 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32597 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32599 expandPath : function(path, attr, callback){
32600 attr = attr || "id";
32601 var keys = path.split(this.pathSeparator);
32602 var curNode = this.root;
32603 if(curNode.attributes[attr] != keys[1]){ // invalid root
32605 callback(false, null);
32610 var f = function(){
32611 if(++index == keys.length){
32613 callback(true, curNode);
32617 var c = curNode.findChild(attr, keys[index]);
32620 callback(false, curNode);
32625 c.expand(false, false, f);
32627 curNode.expand(false, false, f);
32631 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32632 * @param {String} path
32633 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32634 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32635 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32637 selectPath : function(path, attr, callback){
32638 attr = attr || "id";
32639 var keys = path.split(this.pathSeparator);
32640 var v = keys.pop();
32641 if(keys.length > 0){
32642 var f = function(success, node){
32643 if(success && node){
32644 var n = node.findChild(attr, v);
32650 }else if(callback){
32651 callback(false, n);
32655 callback(false, n);
32659 this.expandPath(keys.join(this.pathSeparator), attr, f);
32661 this.root.select();
32663 callback(true, this.root);
32668 getTreeEl : function(){
32673 * Trigger rendering of this TreePanel
32675 render : function(){
32676 if (this.innerCt) {
32677 return this; // stop it rendering more than once!!
32680 this.innerCt = this.el.createChild({tag:"ul",
32681 cls:"x-tree-root-ct " +
32682 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32684 if(this.containerScroll){
32685 Roo.dd.ScrollManager.register(this.el);
32687 if((this.enableDD || this.enableDrop) && !this.dropZone){
32689 * The dropZone used by this tree if drop is enabled
32690 * @type Roo.tree.TreeDropZone
32692 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32693 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32696 if((this.enableDD || this.enableDrag) && !this.dragZone){
32698 * The dragZone used by this tree if drag is enabled
32699 * @type Roo.tree.TreeDragZone
32701 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32702 ddGroup: this.ddGroup || "TreeDD",
32703 scroll: this.ddScroll
32706 this.getSelectionModel().init(this);
32708 Roo.log("ROOT not set in tree");
32711 this.root.render();
32712 if(!this.rootVisible){
32713 this.root.renderChildren();
32719 * Ext JS Library 1.1.1
32720 * Copyright(c) 2006-2007, Ext JS, LLC.
32722 * Originally Released Under LGPL - original licence link has changed is not relivant.
32725 * <script type="text/javascript">
32730 * @class Roo.tree.DefaultSelectionModel
32731 * @extends Roo.util.Observable
32732 * The default single selection for a TreePanel.
32733 * @param {Object} cfg Configuration
32735 Roo.tree.DefaultSelectionModel = function(cfg){
32736 this.selNode = null;
32742 * @event selectionchange
32743 * Fires when the selected node changes
32744 * @param {DefaultSelectionModel} this
32745 * @param {TreeNode} node the new selection
32747 "selectionchange" : true,
32750 * @event beforeselect
32751 * Fires before the selected node changes, return false to cancel the change
32752 * @param {DefaultSelectionModel} this
32753 * @param {TreeNode} node the new selection
32754 * @param {TreeNode} node the old selection
32756 "beforeselect" : true
32759 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32762 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32763 init : function(tree){
32765 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32766 tree.on("click", this.onNodeClick, this);
32769 onNodeClick : function(node, e){
32770 if (e.ctrlKey && this.selNode == node) {
32771 this.unselect(node);
32779 * @param {TreeNode} node The node to select
32780 * @return {TreeNode} The selected node
32782 select : function(node){
32783 var last = this.selNode;
32784 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32786 last.ui.onSelectedChange(false);
32788 this.selNode = node;
32789 node.ui.onSelectedChange(true);
32790 this.fireEvent("selectionchange", this, node, last);
32797 * @param {TreeNode} node The node to unselect
32799 unselect : function(node){
32800 if(this.selNode == node){
32801 this.clearSelections();
32806 * Clear all selections
32808 clearSelections : function(){
32809 var n = this.selNode;
32811 n.ui.onSelectedChange(false);
32812 this.selNode = null;
32813 this.fireEvent("selectionchange", this, null);
32819 * Get the selected node
32820 * @return {TreeNode} The selected node
32822 getSelectedNode : function(){
32823 return this.selNode;
32827 * Returns true if the node is selected
32828 * @param {TreeNode} node The node to check
32829 * @return {Boolean}
32831 isSelected : function(node){
32832 return this.selNode == node;
32836 * Selects the node above the selected node in the tree, intelligently walking the nodes
32837 * @return TreeNode The new selection
32839 selectPrevious : function(){
32840 var s = this.selNode || this.lastSelNode;
32844 var ps = s.previousSibling;
32846 if(!ps.isExpanded() || ps.childNodes.length < 1){
32847 return this.select(ps);
32849 var lc = ps.lastChild;
32850 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32853 return this.select(lc);
32855 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32856 return this.select(s.parentNode);
32862 * Selects the node above the selected node in the tree, intelligently walking the nodes
32863 * @return TreeNode The new selection
32865 selectNext : function(){
32866 var s = this.selNode || this.lastSelNode;
32870 if(s.firstChild && s.isExpanded()){
32871 return this.select(s.firstChild);
32872 }else if(s.nextSibling){
32873 return this.select(s.nextSibling);
32874 }else if(s.parentNode){
32876 s.parentNode.bubble(function(){
32877 if(this.nextSibling){
32878 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32887 onKeyDown : function(e){
32888 var s = this.selNode || this.lastSelNode;
32889 // undesirable, but required
32894 var k = e.getKey();
32902 this.selectPrevious();
32905 e.preventDefault();
32906 if(s.hasChildNodes()){
32907 if(!s.isExpanded()){
32909 }else if(s.firstChild){
32910 this.select(s.firstChild, e);
32915 e.preventDefault();
32916 if(s.hasChildNodes() && s.isExpanded()){
32918 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32919 this.select(s.parentNode, e);
32927 * @class Roo.tree.MultiSelectionModel
32928 * @extends Roo.util.Observable
32929 * Multi selection for a TreePanel.
32930 * @param {Object} cfg Configuration
32932 Roo.tree.MultiSelectionModel = function(){
32933 this.selNodes = [];
32937 * @event selectionchange
32938 * Fires when the selected nodes change
32939 * @param {MultiSelectionModel} this
32940 * @param {Array} nodes Array of the selected nodes
32942 "selectionchange" : true
32944 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32948 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32949 init : function(tree){
32951 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32952 tree.on("click", this.onNodeClick, this);
32955 onNodeClick : function(node, e){
32956 this.select(node, e, e.ctrlKey);
32961 * @param {TreeNode} node The node to select
32962 * @param {EventObject} e (optional) An event associated with the selection
32963 * @param {Boolean} keepExisting True to retain existing selections
32964 * @return {TreeNode} The selected node
32966 select : function(node, e, keepExisting){
32967 if(keepExisting !== true){
32968 this.clearSelections(true);
32970 if(this.isSelected(node)){
32971 this.lastSelNode = node;
32974 this.selNodes.push(node);
32975 this.selMap[node.id] = node;
32976 this.lastSelNode = node;
32977 node.ui.onSelectedChange(true);
32978 this.fireEvent("selectionchange", this, this.selNodes);
32984 * @param {TreeNode} node The node to unselect
32986 unselect : function(node){
32987 if(this.selMap[node.id]){
32988 node.ui.onSelectedChange(false);
32989 var sn = this.selNodes;
32992 index = sn.indexOf(node);
32994 for(var i = 0, len = sn.length; i < len; i++){
33002 this.selNodes.splice(index, 1);
33004 delete this.selMap[node.id];
33005 this.fireEvent("selectionchange", this, this.selNodes);
33010 * Clear all selections
33012 clearSelections : function(suppressEvent){
33013 var sn = this.selNodes;
33015 for(var i = 0, len = sn.length; i < len; i++){
33016 sn[i].ui.onSelectedChange(false);
33018 this.selNodes = [];
33020 if(suppressEvent !== true){
33021 this.fireEvent("selectionchange", this, this.selNodes);
33027 * Returns true if the node is selected
33028 * @param {TreeNode} node The node to check
33029 * @return {Boolean}
33031 isSelected : function(node){
33032 return this.selMap[node.id] ? true : false;
33036 * Returns an array of the selected nodes
33039 getSelectedNodes : function(){
33040 return this.selNodes;
33043 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33045 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33047 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33050 * Ext JS Library 1.1.1
33051 * Copyright(c) 2006-2007, Ext JS, LLC.
33053 * Originally Released Under LGPL - original licence link has changed is not relivant.
33056 * <script type="text/javascript">
33060 * @class Roo.tree.TreeNode
33061 * @extends Roo.data.Node
33062 * @cfg {String} text The text for this node
33063 * @cfg {Boolean} expanded true to start the node expanded
33064 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33065 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33066 * @cfg {Boolean} disabled true to start the node disabled
33067 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33068 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33069 * @cfg {String} cls A css class to be added to the node
33070 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33071 * @cfg {String} href URL of the link used for the node (defaults to #)
33072 * @cfg {String} hrefTarget target frame for the link
33073 * @cfg {String} qtip An Ext QuickTip for the node
33074 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33075 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33076 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33077 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33078 * (defaults to undefined with no checkbox rendered)
33080 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33082 Roo.tree.TreeNode = function(attributes){
33083 attributes = attributes || {};
33084 if(typeof attributes == "string"){
33085 attributes = {text: attributes};
33087 this.childrenRendered = false;
33088 this.rendered = false;
33089 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33090 this.expanded = attributes.expanded === true;
33091 this.isTarget = attributes.isTarget !== false;
33092 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33093 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33096 * Read-only. The text for this node. To change it use setText().
33099 this.text = attributes.text;
33101 * True if this node is disabled.
33104 this.disabled = attributes.disabled === true;
33108 * @event textchange
33109 * Fires when the text for this node is changed
33110 * @param {Node} this This node
33111 * @param {String} text The new text
33112 * @param {String} oldText The old text
33114 "textchange" : true,
33116 * @event beforeexpand
33117 * Fires before this node is expanded, return false to cancel.
33118 * @param {Node} this This node
33119 * @param {Boolean} deep
33120 * @param {Boolean} anim
33122 "beforeexpand" : true,
33124 * @event beforecollapse
33125 * Fires before this node is collapsed, return false to cancel.
33126 * @param {Node} this This node
33127 * @param {Boolean} deep
33128 * @param {Boolean} anim
33130 "beforecollapse" : true,
33133 * Fires when this node is expanded
33134 * @param {Node} this This node
33138 * @event disabledchange
33139 * Fires when the disabled status of this node changes
33140 * @param {Node} this This node
33141 * @param {Boolean} disabled
33143 "disabledchange" : true,
33146 * Fires when this node is collapsed
33147 * @param {Node} this This node
33151 * @event beforeclick
33152 * Fires before click processing. Return false to cancel the default action.
33153 * @param {Node} this This node
33154 * @param {Roo.EventObject} e The event object
33156 "beforeclick":true,
33158 * @event checkchange
33159 * Fires when a node with a checkbox's checked property changes
33160 * @param {Node} this This node
33161 * @param {Boolean} checked
33163 "checkchange":true,
33166 * Fires when this node is clicked
33167 * @param {Node} this This node
33168 * @param {Roo.EventObject} e The event object
33173 * Fires when this node is double clicked
33174 * @param {Node} this This node
33175 * @param {Roo.EventObject} e The event object
33179 * @event contextmenu
33180 * Fires when this node is right clicked
33181 * @param {Node} this This node
33182 * @param {Roo.EventObject} e The event object
33184 "contextmenu":true,
33186 * @event beforechildrenrendered
33187 * Fires right before the child nodes for this node are rendered
33188 * @param {Node} this This node
33190 "beforechildrenrendered":true
33193 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33196 * Read-only. The UI for this node
33199 this.ui = new uiClass(this);
33201 // finally support items[]
33202 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33207 Roo.each(this.attributes.items, function(c) {
33208 this.appendChild(Roo.factory(c,Roo.Tree));
33210 delete this.attributes.items;
33215 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33216 preventHScroll: true,
33218 * Returns true if this node is expanded
33219 * @return {Boolean}
33221 isExpanded : function(){
33222 return this.expanded;
33226 * Returns the UI object for this node
33227 * @return {TreeNodeUI}
33229 getUI : function(){
33233 // private override
33234 setFirstChild : function(node){
33235 var of = this.firstChild;
33236 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33237 if(this.childrenRendered && of && node != of){
33238 of.renderIndent(true, true);
33241 this.renderIndent(true, true);
33245 // private override
33246 setLastChild : function(node){
33247 var ol = this.lastChild;
33248 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33249 if(this.childrenRendered && ol && node != ol){
33250 ol.renderIndent(true, true);
33253 this.renderIndent(true, true);
33257 // these methods are overridden to provide lazy rendering support
33258 // private override
33259 appendChild : function()
33261 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33262 if(node && this.childrenRendered){
33265 this.ui.updateExpandIcon();
33269 // private override
33270 removeChild : function(node){
33271 this.ownerTree.getSelectionModel().unselect(node);
33272 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33273 // if it's been rendered remove dom node
33274 if(this.childrenRendered){
33277 if(this.childNodes.length < 1){
33278 this.collapse(false, false);
33280 this.ui.updateExpandIcon();
33282 if(!this.firstChild) {
33283 this.childrenRendered = false;
33288 // private override
33289 insertBefore : function(node, refNode){
33290 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33291 if(newNode && refNode && this.childrenRendered){
33294 this.ui.updateExpandIcon();
33299 * Sets the text for this node
33300 * @param {String} text
33302 setText : function(text){
33303 var oldText = this.text;
33305 this.attributes.text = text;
33306 if(this.rendered){ // event without subscribing
33307 this.ui.onTextChange(this, text, oldText);
33309 this.fireEvent("textchange", this, text, oldText);
33313 * Triggers selection of this node
33315 select : function(){
33316 this.getOwnerTree().getSelectionModel().select(this);
33320 * Triggers deselection of this node
33322 unselect : function(){
33323 this.getOwnerTree().getSelectionModel().unselect(this);
33327 * Returns true if this node is selected
33328 * @return {Boolean}
33330 isSelected : function(){
33331 return this.getOwnerTree().getSelectionModel().isSelected(this);
33335 * Expand this node.
33336 * @param {Boolean} deep (optional) True to expand all children as well
33337 * @param {Boolean} anim (optional) false to cancel the default animation
33338 * @param {Function} callback (optional) A callback to be called when
33339 * expanding this node completes (does not wait for deep expand to complete).
33340 * Called with 1 parameter, this node.
33342 expand : function(deep, anim, callback){
33343 if(!this.expanded){
33344 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33347 if(!this.childrenRendered){
33348 this.renderChildren();
33350 this.expanded = true;
33351 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33352 this.ui.animExpand(function(){
33353 this.fireEvent("expand", this);
33354 if(typeof callback == "function"){
33358 this.expandChildNodes(true);
33360 }.createDelegate(this));
33364 this.fireEvent("expand", this);
33365 if(typeof callback == "function"){
33370 if(typeof callback == "function"){
33375 this.expandChildNodes(true);
33379 isHiddenRoot : function(){
33380 return this.isRoot && !this.getOwnerTree().rootVisible;
33384 * Collapse this node.
33385 * @param {Boolean} deep (optional) True to collapse all children as well
33386 * @param {Boolean} anim (optional) false to cancel the default animation
33388 collapse : function(deep, anim){
33389 if(this.expanded && !this.isHiddenRoot()){
33390 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33393 this.expanded = false;
33394 if((this.getOwnerTree().animate && anim !== false) || anim){
33395 this.ui.animCollapse(function(){
33396 this.fireEvent("collapse", this);
33398 this.collapseChildNodes(true);
33400 }.createDelegate(this));
33403 this.ui.collapse();
33404 this.fireEvent("collapse", this);
33408 var cs = this.childNodes;
33409 for(var i = 0, len = cs.length; i < len; i++) {
33410 cs[i].collapse(true, false);
33416 delayedExpand : function(delay){
33417 if(!this.expandProcId){
33418 this.expandProcId = this.expand.defer(delay, this);
33423 cancelExpand : function(){
33424 if(this.expandProcId){
33425 clearTimeout(this.expandProcId);
33427 this.expandProcId = false;
33431 * Toggles expanded/collapsed state of the node
33433 toggle : function(){
33442 * Ensures all parent nodes are expanded
33444 ensureVisible : function(callback){
33445 var tree = this.getOwnerTree();
33446 tree.expandPath(this.parentNode.getPath(), false, function(){
33447 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33448 Roo.callback(callback);
33449 }.createDelegate(this));
33453 * Expand all child nodes
33454 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33456 expandChildNodes : function(deep){
33457 var cs = this.childNodes;
33458 for(var i = 0, len = cs.length; i < len; i++) {
33459 cs[i].expand(deep);
33464 * Collapse all child nodes
33465 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33467 collapseChildNodes : function(deep){
33468 var cs = this.childNodes;
33469 for(var i = 0, len = cs.length; i < len; i++) {
33470 cs[i].collapse(deep);
33475 * Disables this node
33477 disable : function(){
33478 this.disabled = true;
33480 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33481 this.ui.onDisableChange(this, true);
33483 this.fireEvent("disabledchange", this, true);
33487 * Enables this node
33489 enable : function(){
33490 this.disabled = false;
33491 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33492 this.ui.onDisableChange(this, false);
33494 this.fireEvent("disabledchange", this, false);
33498 renderChildren : function(suppressEvent){
33499 if(suppressEvent !== false){
33500 this.fireEvent("beforechildrenrendered", this);
33502 var cs = this.childNodes;
33503 for(var i = 0, len = cs.length; i < len; i++){
33504 cs[i].render(true);
33506 this.childrenRendered = true;
33510 sort : function(fn, scope){
33511 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33512 if(this.childrenRendered){
33513 var cs = this.childNodes;
33514 for(var i = 0, len = cs.length; i < len; i++){
33515 cs[i].render(true);
33521 render : function(bulkRender){
33522 this.ui.render(bulkRender);
33523 if(!this.rendered){
33524 this.rendered = true;
33526 this.expanded = false;
33527 this.expand(false, false);
33533 renderIndent : function(deep, refresh){
33535 this.ui.childIndent = null;
33537 this.ui.renderIndent();
33538 if(deep === true && this.childrenRendered){
33539 var cs = this.childNodes;
33540 for(var i = 0, len = cs.length; i < len; i++){
33541 cs[i].renderIndent(true, refresh);
33547 * Ext JS Library 1.1.1
33548 * Copyright(c) 2006-2007, Ext JS, LLC.
33550 * Originally Released Under LGPL - original licence link has changed is not relivant.
33553 * <script type="text/javascript">
33557 * @class Roo.tree.AsyncTreeNode
33558 * @extends Roo.tree.TreeNode
33559 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33561 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33563 Roo.tree.AsyncTreeNode = function(config){
33564 this.loaded = false;
33565 this.loading = false;
33566 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33568 * @event beforeload
33569 * Fires before this node is loaded, return false to cancel
33570 * @param {Node} this This node
33572 this.addEvents({'beforeload':true, 'load': true});
33575 * Fires when this node is loaded
33576 * @param {Node} this This node
33579 * The loader used by this node (defaults to using the tree's defined loader)
33584 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33585 expand : function(deep, anim, callback){
33586 if(this.loading){ // if an async load is already running, waiting til it's done
33588 var f = function(){
33589 if(!this.loading){ // done loading
33590 clearInterval(timer);
33591 this.expand(deep, anim, callback);
33593 }.createDelegate(this);
33594 timer = setInterval(f, 200);
33598 if(this.fireEvent("beforeload", this) === false){
33601 this.loading = true;
33602 this.ui.beforeLoad(this);
33603 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33605 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33609 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33613 * Returns true if this node is currently loading
33614 * @return {Boolean}
33616 isLoading : function(){
33617 return this.loading;
33620 loadComplete : function(deep, anim, callback){
33621 this.loading = false;
33622 this.loaded = true;
33623 this.ui.afterLoad(this);
33624 this.fireEvent("load", this);
33625 this.expand(deep, anim, callback);
33629 * Returns true if this node has been loaded
33630 * @return {Boolean}
33632 isLoaded : function(){
33633 return this.loaded;
33636 hasChildNodes : function(){
33637 if(!this.isLeaf() && !this.loaded){
33640 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33645 * Trigger a reload for this node
33646 * @param {Function} callback
33648 reload : function(callback){
33649 this.collapse(false, false);
33650 while(this.firstChild){
33651 this.removeChild(this.firstChild);
33653 this.childrenRendered = false;
33654 this.loaded = false;
33655 if(this.isHiddenRoot()){
33656 this.expanded = false;
33658 this.expand(false, false, callback);
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">
33672 * @class Roo.tree.TreeNodeUI
33674 * @param {Object} node The node to render
33675 * The TreeNode UI implementation is separate from the
33676 * tree implementation. Unless you are customizing the tree UI,
33677 * you should never have to use this directly.
33679 Roo.tree.TreeNodeUI = function(node){
33681 this.rendered = false;
33682 this.animating = false;
33683 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33686 Roo.tree.TreeNodeUI.prototype = {
33687 removeChild : function(node){
33689 this.ctNode.removeChild(node.ui.getEl());
33693 beforeLoad : function(){
33694 this.addClass("x-tree-node-loading");
33697 afterLoad : function(){
33698 this.removeClass("x-tree-node-loading");
33701 onTextChange : function(node, text, oldText){
33703 this.textNode.innerHTML = text;
33707 onDisableChange : function(node, state){
33708 this.disabled = state;
33710 this.addClass("x-tree-node-disabled");
33712 this.removeClass("x-tree-node-disabled");
33716 onSelectedChange : function(state){
33719 this.addClass("x-tree-selected");
33722 this.removeClass("x-tree-selected");
33726 onMove : function(tree, node, oldParent, newParent, index, refNode){
33727 this.childIndent = null;
33729 var targetNode = newParent.ui.getContainer();
33730 if(!targetNode){//target not rendered
33731 this.holder = document.createElement("div");
33732 this.holder.appendChild(this.wrap);
33735 var insertBefore = refNode ? refNode.ui.getEl() : null;
33737 targetNode.insertBefore(this.wrap, insertBefore);
33739 targetNode.appendChild(this.wrap);
33741 this.node.renderIndent(true);
33745 addClass : function(cls){
33747 Roo.fly(this.elNode).addClass(cls);
33751 removeClass : function(cls){
33753 Roo.fly(this.elNode).removeClass(cls);
33757 remove : function(){
33759 this.holder = document.createElement("div");
33760 this.holder.appendChild(this.wrap);
33764 fireEvent : function(){
33765 return this.node.fireEvent.apply(this.node, arguments);
33768 initEvents : function(){
33769 this.node.on("move", this.onMove, this);
33770 var E = Roo.EventManager;
33771 var a = this.anchor;
33773 var el = Roo.fly(a, '_treeui');
33775 if(Roo.isOpera){ // opera render bug ignores the CSS
33776 el.setStyle("text-decoration", "none");
33779 el.on("click", this.onClick, this);
33780 el.on("dblclick", this.onDblClick, this);
33783 Roo.EventManager.on(this.checkbox,
33784 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33787 el.on("contextmenu", this.onContextMenu, this);
33789 var icon = Roo.fly(this.iconNode);
33790 icon.on("click", this.onClick, this);
33791 icon.on("dblclick", this.onDblClick, this);
33792 icon.on("contextmenu", this.onContextMenu, this);
33793 E.on(this.ecNode, "click", this.ecClick, this, true);
33795 if(this.node.disabled){
33796 this.addClass("x-tree-node-disabled");
33798 if(this.node.hidden){
33799 this.addClass("x-tree-node-disabled");
33801 var ot = this.node.getOwnerTree();
33802 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33803 if(dd && (!this.node.isRoot || ot.rootVisible)){
33804 Roo.dd.Registry.register(this.elNode, {
33806 handles: this.getDDHandles(),
33812 getDDHandles : function(){
33813 return [this.iconNode, this.textNode];
33818 this.wrap.style.display = "none";
33824 this.wrap.style.display = "";
33828 onContextMenu : function(e){
33829 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33830 e.preventDefault();
33832 this.fireEvent("contextmenu", this.node, e);
33836 onClick : function(e){
33841 if(this.fireEvent("beforeclick", this.node, e) !== false){
33842 if(!this.disabled && this.node.attributes.href){
33843 this.fireEvent("click", this.node, e);
33846 e.preventDefault();
33851 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33852 this.node.toggle();
33855 this.fireEvent("click", this.node, e);
33861 onDblClick : function(e){
33862 e.preventDefault();
33867 this.toggleCheck();
33869 if(!this.animating && this.node.hasChildNodes()){
33870 this.node.toggle();
33872 this.fireEvent("dblclick", this.node, e);
33875 onCheckChange : function(){
33876 var checked = this.checkbox.checked;
33877 this.node.attributes.checked = checked;
33878 this.fireEvent('checkchange', this.node, checked);
33881 ecClick : function(e){
33882 if(!this.animating && this.node.hasChildNodes()){
33883 this.node.toggle();
33887 startDrop : function(){
33888 this.dropping = true;
33891 // delayed drop so the click event doesn't get fired on a drop
33892 endDrop : function(){
33893 setTimeout(function(){
33894 this.dropping = false;
33895 }.createDelegate(this), 50);
33898 expand : function(){
33899 this.updateExpandIcon();
33900 this.ctNode.style.display = "";
33903 focus : function(){
33904 if(!this.node.preventHScroll){
33905 try{this.anchor.focus();
33907 }else if(!Roo.isIE){
33909 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33910 var l = noscroll.scrollLeft;
33911 this.anchor.focus();
33912 noscroll.scrollLeft = l;
33917 toggleCheck : function(value){
33918 var cb = this.checkbox;
33920 cb.checked = (value === undefined ? !cb.checked : value);
33926 this.anchor.blur();
33930 animExpand : function(callback){
33931 var ct = Roo.get(this.ctNode);
33933 if(!this.node.hasChildNodes()){
33934 this.updateExpandIcon();
33935 this.ctNode.style.display = "";
33936 Roo.callback(callback);
33939 this.animating = true;
33940 this.updateExpandIcon();
33943 callback : function(){
33944 this.animating = false;
33945 Roo.callback(callback);
33948 duration: this.node.ownerTree.duration || .25
33952 highlight : function(){
33953 var tree = this.node.getOwnerTree();
33954 Roo.fly(this.wrap).highlight(
33955 tree.hlColor || "C3DAF9",
33956 {endColor: tree.hlBaseColor}
33960 collapse : function(){
33961 this.updateExpandIcon();
33962 this.ctNode.style.display = "none";
33965 animCollapse : function(callback){
33966 var ct = Roo.get(this.ctNode);
33967 ct.enableDisplayMode('block');
33970 this.animating = true;
33971 this.updateExpandIcon();
33974 callback : function(){
33975 this.animating = false;
33976 Roo.callback(callback);
33979 duration: this.node.ownerTree.duration || .25
33983 getContainer : function(){
33984 return this.ctNode;
33987 getEl : function(){
33991 appendDDGhost : function(ghostNode){
33992 ghostNode.appendChild(this.elNode.cloneNode(true));
33995 getDDRepairXY : function(){
33996 return Roo.lib.Dom.getXY(this.iconNode);
33999 onRender : function(){
34003 render : function(bulkRender){
34004 var n = this.node, a = n.attributes;
34005 var targetNode = n.parentNode ?
34006 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34008 if(!this.rendered){
34009 this.rendered = true;
34011 this.renderElements(n, a, targetNode, bulkRender);
34014 if(this.textNode.setAttributeNS){
34015 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34017 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34020 this.textNode.setAttribute("ext:qtip", a.qtip);
34022 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34025 }else if(a.qtipCfg){
34026 a.qtipCfg.target = Roo.id(this.textNode);
34027 Roo.QuickTips.register(a.qtipCfg);
34030 if(!this.node.expanded){
34031 this.updateExpandIcon();
34034 if(bulkRender === true) {
34035 targetNode.appendChild(this.wrap);
34040 renderElements : function(n, a, targetNode, bulkRender)
34042 // add some indent caching, this helps performance when rendering a large tree
34043 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34044 var t = n.getOwnerTree();
34045 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34046 if (typeof(n.attributes.html) != 'undefined') {
34047 txt = n.attributes.html;
34049 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34050 var cb = typeof a.checked == 'boolean';
34051 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34052 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34053 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34054 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34055 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34056 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34057 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34058 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34059 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34060 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34063 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34064 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34065 n.nextSibling.ui.getEl(), buf.join(""));
34067 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34070 this.elNode = this.wrap.childNodes[0];
34071 this.ctNode = this.wrap.childNodes[1];
34072 var cs = this.elNode.childNodes;
34073 this.indentNode = cs[0];
34074 this.ecNode = cs[1];
34075 this.iconNode = cs[2];
34078 this.checkbox = cs[3];
34081 this.anchor = cs[index];
34082 this.textNode = cs[index].firstChild;
34085 getAnchor : function(){
34086 return this.anchor;
34089 getTextEl : function(){
34090 return this.textNode;
34093 getIconEl : function(){
34094 return this.iconNode;
34097 isChecked : function(){
34098 return this.checkbox ? this.checkbox.checked : false;
34101 updateExpandIcon : function(){
34103 var n = this.node, c1, c2;
34104 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34105 var hasChild = n.hasChildNodes();
34109 c1 = "x-tree-node-collapsed";
34110 c2 = "x-tree-node-expanded";
34113 c1 = "x-tree-node-expanded";
34114 c2 = "x-tree-node-collapsed";
34117 this.removeClass("x-tree-node-leaf");
34118 this.wasLeaf = false;
34120 if(this.c1 != c1 || this.c2 != c2){
34121 Roo.fly(this.elNode).replaceClass(c1, c2);
34122 this.c1 = c1; this.c2 = c2;
34125 // this changes non-leafs into leafs if they have no children.
34126 // it's not very rational behaviour..
34128 if(!this.wasLeaf && this.node.leaf){
34129 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34132 this.wasLeaf = true;
34135 var ecc = "x-tree-ec-icon "+cls;
34136 if(this.ecc != ecc){
34137 this.ecNode.className = ecc;
34143 getChildIndent : function(){
34144 if(!this.childIndent){
34148 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34150 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34152 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34157 this.childIndent = buf.join("");
34159 return this.childIndent;
34162 renderIndent : function(){
34165 var p = this.node.parentNode;
34167 indent = p.ui.getChildIndent();
34169 if(this.indentMarkup != indent){ // don't rerender if not required
34170 this.indentNode.innerHTML = indent;
34171 this.indentMarkup = indent;
34173 this.updateExpandIcon();
34178 Roo.tree.RootTreeNodeUI = function(){
34179 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34181 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34182 render : function(){
34183 if(!this.rendered){
34184 var targetNode = this.node.ownerTree.innerCt.dom;
34185 this.node.expanded = true;
34186 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34187 this.wrap = this.ctNode = targetNode.firstChild;
34190 collapse : function(){
34192 expand : function(){
34196 * Ext JS Library 1.1.1
34197 * Copyright(c) 2006-2007, Ext JS, LLC.
34199 * Originally Released Under LGPL - original licence link has changed is not relivant.
34202 * <script type="text/javascript">
34205 * @class Roo.tree.TreeLoader
34206 * @extends Roo.util.Observable
34207 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34208 * nodes from a specified URL. The response must be a javascript Array definition
34209 * who's elements are node definition objects. eg:
34214 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34215 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34222 * The old style respose with just an array is still supported, but not recommended.
34225 * A server request is sent, and child nodes are loaded only when a node is expanded.
34226 * The loading node's id is passed to the server under the parameter name "node" to
34227 * enable the server to produce the correct child nodes.
34229 * To pass extra parameters, an event handler may be attached to the "beforeload"
34230 * event, and the parameters specified in the TreeLoader's baseParams property:
34232 myTreeLoader.on("beforeload", function(treeLoader, node) {
34233 this.baseParams.category = node.attributes.category;
34236 * This would pass an HTTP parameter called "category" to the server containing
34237 * the value of the Node's "category" attribute.
34239 * Creates a new Treeloader.
34240 * @param {Object} config A config object containing config properties.
34242 Roo.tree.TreeLoader = function(config){
34243 this.baseParams = {};
34244 this.requestMethod = "POST";
34245 Roo.apply(this, config);
34250 * @event beforeload
34251 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34252 * @param {Object} This TreeLoader object.
34253 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34254 * @param {Object} callback The callback function specified in the {@link #load} call.
34259 * Fires when the node has been successfuly loaded.
34260 * @param {Object} This TreeLoader object.
34261 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34262 * @param {Object} response The response object containing the data from the server.
34266 * @event loadexception
34267 * Fires if the network request failed.
34268 * @param {Object} This TreeLoader object.
34269 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34270 * @param {Object} response The response object containing the data from the server.
34272 loadexception : true,
34275 * Fires before a node is created, enabling you to return custom Node types
34276 * @param {Object} This TreeLoader object.
34277 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34282 Roo.tree.TreeLoader.superclass.constructor.call(this);
34285 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34287 * @cfg {String} dataUrl The URL from which to request a Json string which
34288 * specifies an array of node definition object representing the child nodes
34292 * @cfg {String} requestMethod either GET or POST
34293 * defaults to POST (due to BC)
34297 * @cfg {Object} baseParams (optional) An object containing properties which
34298 * specify HTTP parameters to be passed to each request for child nodes.
34301 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34302 * created by this loader. If the attributes sent by the server have an attribute in this object,
34303 * they take priority.
34306 * @cfg {Object} uiProviders (optional) An object containing properties which
34308 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34309 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34310 * <i>uiProvider</i> attribute of a returned child node is a string rather
34311 * than a reference to a TreeNodeUI implementation, this that string value
34312 * is used as a property name in the uiProviders object. You can define the provider named
34313 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34318 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34319 * child nodes before loading.
34321 clearOnLoad : true,
34324 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34325 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34326 * Grid query { data : [ .....] }
34331 * @cfg {String} queryParam (optional)
34332 * Name of the query as it will be passed on the querystring (defaults to 'node')
34333 * eg. the request will be ?node=[id]
34340 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34341 * This is called automatically when a node is expanded, but may be used to reload
34342 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34343 * @param {Roo.tree.TreeNode} node
34344 * @param {Function} callback
34346 load : function(node, callback){
34347 if(this.clearOnLoad){
34348 while(node.firstChild){
34349 node.removeChild(node.firstChild);
34352 if(node.attributes.children){ // preloaded json children
34353 var cs = node.attributes.children;
34354 for(var i = 0, len = cs.length; i < len; i++){
34355 node.appendChild(this.createNode(cs[i]));
34357 if(typeof callback == "function"){
34360 }else if(this.dataUrl){
34361 this.requestData(node, callback);
34365 getParams: function(node){
34366 var buf = [], bp = this.baseParams;
34367 for(var key in bp){
34368 if(typeof bp[key] != "function"){
34369 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34372 var n = this.queryParam === false ? 'node' : this.queryParam;
34373 buf.push(n + "=", encodeURIComponent(node.id));
34374 return buf.join("");
34377 requestData : function(node, callback){
34378 if(this.fireEvent("beforeload", this, node, callback) !== false){
34379 this.transId = Roo.Ajax.request({
34380 method:this.requestMethod,
34381 url: this.dataUrl||this.url,
34382 success: this.handleResponse,
34383 failure: this.handleFailure,
34385 argument: {callback: callback, node: node},
34386 params: this.getParams(node)
34389 // if the load is cancelled, make sure we notify
34390 // the node that we are done
34391 if(typeof callback == "function"){
34397 isLoading : function(){
34398 return this.transId ? true : false;
34401 abort : function(){
34402 if(this.isLoading()){
34403 Roo.Ajax.abort(this.transId);
34408 createNode : function(attr)
34410 // apply baseAttrs, nice idea Corey!
34411 if(this.baseAttrs){
34412 Roo.applyIf(attr, this.baseAttrs);
34414 if(this.applyLoader !== false){
34415 attr.loader = this;
34417 // uiProvider = depreciated..
34419 if(typeof(attr.uiProvider) == 'string'){
34420 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34421 /** eval:var:attr */ eval(attr.uiProvider);
34423 if(typeof(this.uiProviders['default']) != 'undefined') {
34424 attr.uiProvider = this.uiProviders['default'];
34427 this.fireEvent('create', this, attr);
34429 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34431 new Roo.tree.TreeNode(attr) :
34432 new Roo.tree.AsyncTreeNode(attr));
34435 processResponse : function(response, node, callback)
34437 var json = response.responseText;
34440 var o = Roo.decode(json);
34442 if (this.root === false && typeof(o.success) != undefined) {
34443 this.root = 'data'; // the default behaviour for list like data..
34446 if (this.root !== false && !o.success) {
34447 // it's a failure condition.
34448 var a = response.argument;
34449 this.fireEvent("loadexception", this, a.node, response);
34450 Roo.log("Load failed - should have a handler really");
34456 if (this.root !== false) {
34460 for(var i = 0, len = o.length; i < len; i++){
34461 var n = this.createNode(o[i]);
34463 node.appendChild(n);
34466 if(typeof callback == "function"){
34467 callback(this, node);
34470 this.handleFailure(response);
34474 handleResponse : function(response){
34475 this.transId = false;
34476 var a = response.argument;
34477 this.processResponse(response, a.node, a.callback);
34478 this.fireEvent("load", this, a.node, response);
34481 handleFailure : function(response)
34483 // should handle failure better..
34484 this.transId = false;
34485 var a = response.argument;
34486 this.fireEvent("loadexception", this, a.node, response);
34487 if(typeof a.callback == "function"){
34488 a.callback(this, a.node);
34493 * Ext JS Library 1.1.1
34494 * Copyright(c) 2006-2007, Ext JS, LLC.
34496 * Originally Released Under LGPL - original licence link has changed is not relivant.
34499 * <script type="text/javascript">
34503 * @class Roo.tree.TreeFilter
34504 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34505 * @param {TreePanel} tree
34506 * @param {Object} config (optional)
34508 Roo.tree.TreeFilter = function(tree, config){
34510 this.filtered = {};
34511 Roo.apply(this, config);
34514 Roo.tree.TreeFilter.prototype = {
34521 * Filter the data by a specific attribute.
34522 * @param {String/RegExp} value Either string that the attribute value
34523 * should start with or a RegExp to test against the attribute
34524 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34525 * @param {TreeNode} startNode (optional) The node to start the filter at.
34527 filter : function(value, attr, startNode){
34528 attr = attr || "text";
34530 if(typeof value == "string"){
34531 var vlen = value.length;
34532 // auto clear empty filter
34533 if(vlen == 0 && this.clearBlank){
34537 value = value.toLowerCase();
34539 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34541 }else if(value.exec){ // regex?
34543 return value.test(n.attributes[attr]);
34546 throw 'Illegal filter type, must be string or regex';
34548 this.filterBy(f, null, startNode);
34552 * Filter by a function. The passed function will be called with each
34553 * node in the tree (or from the startNode). If the function returns true, the node is kept
34554 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34555 * @param {Function} fn The filter function
34556 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34558 filterBy : function(fn, scope, startNode){
34559 startNode = startNode || this.tree.root;
34560 if(this.autoClear){
34563 var af = this.filtered, rv = this.reverse;
34564 var f = function(n){
34565 if(n == startNode){
34571 var m = fn.call(scope || n, n);
34579 startNode.cascade(f);
34582 if(typeof id != "function"){
34584 if(n && n.parentNode){
34585 n.parentNode.removeChild(n);
34593 * Clears the current filter. Note: with the "remove" option
34594 * set a filter cannot be cleared.
34596 clear : function(){
34598 var af = this.filtered;
34600 if(typeof id != "function"){
34607 this.filtered = {};
34612 * Ext JS Library 1.1.1
34613 * Copyright(c) 2006-2007, Ext JS, LLC.
34615 * Originally Released Under LGPL - original licence link has changed is not relivant.
34618 * <script type="text/javascript">
34623 * @class Roo.tree.TreeSorter
34624 * Provides sorting of nodes in a TreePanel
34626 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34627 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34628 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34629 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34630 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34631 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34633 * @param {TreePanel} tree
34634 * @param {Object} config
34636 Roo.tree.TreeSorter = function(tree, config){
34637 Roo.apply(this, config);
34638 tree.on("beforechildrenrendered", this.doSort, this);
34639 tree.on("append", this.updateSort, this);
34640 tree.on("insert", this.updateSort, this);
34642 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34643 var p = this.property || "text";
34644 var sortType = this.sortType;
34645 var fs = this.folderSort;
34646 var cs = this.caseSensitive === true;
34647 var leafAttr = this.leafAttr || 'leaf';
34649 this.sortFn = function(n1, n2){
34651 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34654 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34658 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34659 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34661 return dsc ? +1 : -1;
34663 return dsc ? -1 : +1;
34670 Roo.tree.TreeSorter.prototype = {
34671 doSort : function(node){
34672 node.sort(this.sortFn);
34675 compareNodes : function(n1, n2){
34676 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34679 updateSort : function(tree, node){
34680 if(node.childrenRendered){
34681 this.doSort.defer(1, this, [node]);
34686 * Ext JS Library 1.1.1
34687 * Copyright(c) 2006-2007, Ext JS, LLC.
34689 * Originally Released Under LGPL - original licence link has changed is not relivant.
34692 * <script type="text/javascript">
34695 if(Roo.dd.DropZone){
34697 Roo.tree.TreeDropZone = function(tree, config){
34698 this.allowParentInsert = false;
34699 this.allowContainerDrop = false;
34700 this.appendOnly = false;
34701 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34703 this.lastInsertClass = "x-tree-no-status";
34704 this.dragOverData = {};
34707 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34708 ddGroup : "TreeDD",
34711 expandDelay : 1000,
34713 expandNode : function(node){
34714 if(node.hasChildNodes() && !node.isExpanded()){
34715 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34719 queueExpand : function(node){
34720 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34723 cancelExpand : function(){
34724 if(this.expandProcId){
34725 clearTimeout(this.expandProcId);
34726 this.expandProcId = false;
34730 isValidDropPoint : function(n, pt, dd, e, data){
34731 if(!n || !data){ return false; }
34732 var targetNode = n.node;
34733 var dropNode = data.node;
34734 // default drop rules
34735 if(!(targetNode && targetNode.isTarget && pt)){
34738 if(pt == "append" && targetNode.allowChildren === false){
34741 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34744 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34747 // reuse the object
34748 var overEvent = this.dragOverData;
34749 overEvent.tree = this.tree;
34750 overEvent.target = targetNode;
34751 overEvent.data = data;
34752 overEvent.point = pt;
34753 overEvent.source = dd;
34754 overEvent.rawEvent = e;
34755 overEvent.dropNode = dropNode;
34756 overEvent.cancel = false;
34757 var result = this.tree.fireEvent("nodedragover", overEvent);
34758 return overEvent.cancel === false && result !== false;
34761 getDropPoint : function(e, n, dd)
34765 return tn.allowChildren !== false ? "append" : false; // always append for root
34767 var dragEl = n.ddel;
34768 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34769 var y = Roo.lib.Event.getPageY(e);
34770 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34772 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34773 var noAppend = tn.allowChildren === false;
34774 if(this.appendOnly || tn.parentNode.allowChildren === false){
34775 return noAppend ? false : "append";
34777 var noBelow = false;
34778 if(!this.allowParentInsert){
34779 noBelow = tn.hasChildNodes() && tn.isExpanded();
34781 var q = (b - t) / (noAppend ? 2 : 3);
34782 if(y >= t && y < (t + q)){
34784 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34791 onNodeEnter : function(n, dd, e, data)
34793 this.cancelExpand();
34796 onNodeOver : function(n, dd, e, data)
34799 var pt = this.getDropPoint(e, n, dd);
34802 // auto node expand check
34803 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34804 this.queueExpand(node);
34805 }else if(pt != "append"){
34806 this.cancelExpand();
34809 // set the insert point style on the target node
34810 var returnCls = this.dropNotAllowed;
34811 if(this.isValidDropPoint(n, pt, dd, e, data)){
34816 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34817 cls = "x-tree-drag-insert-above";
34818 }else if(pt == "below"){
34819 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34820 cls = "x-tree-drag-insert-below";
34822 returnCls = "x-tree-drop-ok-append";
34823 cls = "x-tree-drag-append";
34825 if(this.lastInsertClass != cls){
34826 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34827 this.lastInsertClass = cls;
34834 onNodeOut : function(n, dd, e, data){
34836 this.cancelExpand();
34837 this.removeDropIndicators(n);
34840 onNodeDrop : function(n, dd, e, data){
34841 var point = this.getDropPoint(e, n, dd);
34842 var targetNode = n.node;
34843 targetNode.ui.startDrop();
34844 if(!this.isValidDropPoint(n, point, dd, e, data)){
34845 targetNode.ui.endDrop();
34848 // first try to find the drop node
34849 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34852 target: targetNode,
34857 dropNode: dropNode,
34860 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34861 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34862 targetNode.ui.endDrop();
34865 // allow target changing
34866 targetNode = dropEvent.target;
34867 if(point == "append" && !targetNode.isExpanded()){
34868 targetNode.expand(false, null, function(){
34869 this.completeDrop(dropEvent);
34870 }.createDelegate(this));
34872 this.completeDrop(dropEvent);
34877 completeDrop : function(de){
34878 var ns = de.dropNode, p = de.point, t = de.target;
34879 if(!(ns instanceof Array)){
34883 for(var i = 0, len = ns.length; i < len; i++){
34886 t.parentNode.insertBefore(n, t);
34887 }else if(p == "below"){
34888 t.parentNode.insertBefore(n, t.nextSibling);
34894 if(this.tree.hlDrop){
34898 this.tree.fireEvent("nodedrop", de);
34901 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34902 if(this.tree.hlDrop){
34903 dropNode.ui.focus();
34904 dropNode.ui.highlight();
34906 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34909 getTree : function(){
34913 removeDropIndicators : function(n){
34916 Roo.fly(el).removeClass([
34917 "x-tree-drag-insert-above",
34918 "x-tree-drag-insert-below",
34919 "x-tree-drag-append"]);
34920 this.lastInsertClass = "_noclass";
34924 beforeDragDrop : function(target, e, id){
34925 this.cancelExpand();
34929 afterRepair : function(data){
34930 if(data && Roo.enableFx){
34931 data.node.ui.highlight();
34941 * Ext JS Library 1.1.1
34942 * Copyright(c) 2006-2007, Ext JS, LLC.
34944 * Originally Released Under LGPL - original licence link has changed is not relivant.
34947 * <script type="text/javascript">
34951 if(Roo.dd.DragZone){
34952 Roo.tree.TreeDragZone = function(tree, config){
34953 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34957 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34958 ddGroup : "TreeDD",
34960 onBeforeDrag : function(data, e){
34962 return n && n.draggable && !n.disabled;
34966 onInitDrag : function(e){
34967 var data = this.dragData;
34968 this.tree.getSelectionModel().select(data.node);
34969 this.proxy.update("");
34970 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34971 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34974 getRepairXY : function(e, data){
34975 return data.node.ui.getDDRepairXY();
34978 onEndDrag : function(data, e){
34979 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34984 onValidDrop : function(dd, e, id){
34985 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34989 beforeInvalidDrop : function(e, id){
34990 // this scrolls the original position back into view
34991 var sm = this.tree.getSelectionModel();
34992 sm.clearSelections();
34993 sm.select(this.dragData.node);
34998 * Ext JS Library 1.1.1
34999 * Copyright(c) 2006-2007, Ext JS, LLC.
35001 * Originally Released Under LGPL - original licence link has changed is not relivant.
35004 * <script type="text/javascript">
35007 * @class Roo.tree.TreeEditor
35008 * @extends Roo.Editor
35009 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35010 * as the editor field.
35012 * @param {Object} config (used to be the tree panel.)
35013 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35015 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35016 * @cfg {Roo.form.TextField|Object} field The field configuration
35020 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35023 if (oldconfig) { // old style..
35024 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35027 tree = config.tree;
35028 config.field = config.field || {};
35029 config.field.xtype = 'TextField';
35030 field = Roo.factory(config.field, Roo.form);
35032 config = config || {};
35037 * @event beforenodeedit
35038 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35039 * false from the handler of this event.
35040 * @param {Editor} this
35041 * @param {Roo.tree.Node} node
35043 "beforenodeedit" : true
35047 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35051 tree.on('beforeclick', this.beforeNodeClick, this);
35052 tree.getTreeEl().on('mousedown', this.hide, this);
35053 this.on('complete', this.updateNode, this);
35054 this.on('beforestartedit', this.fitToTree, this);
35055 this.on('startedit', this.bindScroll, this, {delay:10});
35056 this.on('specialkey', this.onSpecialKey, this);
35059 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35061 * @cfg {String} alignment
35062 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35068 * @cfg {Boolean} hideEl
35069 * True to hide the bound element while the editor is displayed (defaults to false)
35073 * @cfg {String} cls
35074 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35076 cls: "x-small-editor x-tree-editor",
35078 * @cfg {Boolean} shim
35079 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35085 * @cfg {Number} maxWidth
35086 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35087 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35088 * scroll and client offsets into account prior to each edit.
35095 fitToTree : function(ed, el){
35096 var td = this.tree.getTreeEl().dom, nd = el.dom;
35097 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35098 td.scrollLeft = nd.offsetLeft;
35102 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35103 this.setSize(w, '');
35105 return this.fireEvent('beforenodeedit', this, this.editNode);
35110 triggerEdit : function(node){
35111 this.completeEdit();
35112 this.editNode = node;
35113 this.startEdit(node.ui.textNode, node.text);
35117 bindScroll : function(){
35118 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35122 beforeNodeClick : function(node, e){
35123 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35124 this.lastClick = new Date();
35125 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35127 this.triggerEdit(node);
35134 updateNode : function(ed, value){
35135 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35136 this.editNode.setText(value);
35140 onHide : function(){
35141 Roo.tree.TreeEditor.superclass.onHide.call(this);
35143 this.editNode.ui.focus();
35148 onSpecialKey : function(field, e){
35149 var k = e.getKey();
35153 }else if(k == e.ENTER && !e.hasModifier()){
35155 this.completeEdit();
35158 });//<Script type="text/javascript">
35161 * Ext JS Library 1.1.1
35162 * Copyright(c) 2006-2007, Ext JS, LLC.
35164 * Originally Released Under LGPL - original licence link has changed is not relivant.
35167 * <script type="text/javascript">
35171 * Not documented??? - probably should be...
35174 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35175 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35177 renderElements : function(n, a, targetNode, bulkRender){
35178 //consel.log("renderElements?");
35179 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35181 var t = n.getOwnerTree();
35182 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35184 var cols = t.columns;
35185 var bw = t.borderWidth;
35187 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35188 var cb = typeof a.checked == "boolean";
35189 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35190 var colcls = 'x-t-' + tid + '-c0';
35192 '<li class="x-tree-node">',
35195 '<div class="x-tree-node-el ', a.cls,'">',
35197 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35200 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35201 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35202 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35203 (a.icon ? ' x-tree-node-inline-icon' : ''),
35204 (a.iconCls ? ' '+a.iconCls : ''),
35205 '" unselectable="on" />',
35206 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35207 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35209 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35210 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35211 '<span unselectable="on" qtip="' + tx + '">',
35215 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35216 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35218 for(var i = 1, len = cols.length; i < len; i++){
35220 colcls = 'x-t-' + tid + '-c' +i;
35221 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35222 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35223 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35229 '<div class="x-clear"></div></div>',
35230 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35233 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35234 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35235 n.nextSibling.ui.getEl(), buf.join(""));
35237 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35239 var el = this.wrap.firstChild;
35241 this.elNode = el.firstChild;
35242 this.ranchor = el.childNodes[1];
35243 this.ctNode = this.wrap.childNodes[1];
35244 var cs = el.firstChild.childNodes;
35245 this.indentNode = cs[0];
35246 this.ecNode = cs[1];
35247 this.iconNode = cs[2];
35250 this.checkbox = cs[3];
35253 this.anchor = cs[index];
35255 this.textNode = cs[index].firstChild;
35257 //el.on("click", this.onClick, this);
35258 //el.on("dblclick", this.onDblClick, this);
35261 // console.log(this);
35263 initEvents : function(){
35264 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35267 var a = this.ranchor;
35269 var el = Roo.get(a);
35271 if(Roo.isOpera){ // opera render bug ignores the CSS
35272 el.setStyle("text-decoration", "none");
35275 el.on("click", this.onClick, this);
35276 el.on("dblclick", this.onDblClick, this);
35277 el.on("contextmenu", this.onContextMenu, this);
35281 /*onSelectedChange : function(state){
35284 this.addClass("x-tree-selected");
35287 this.removeClass("x-tree-selected");
35290 addClass : function(cls){
35292 Roo.fly(this.elRow).addClass(cls);
35298 removeClass : function(cls){
35300 Roo.fly(this.elRow).removeClass(cls);
35306 });//<Script type="text/javascript">
35310 * Ext JS Library 1.1.1
35311 * Copyright(c) 2006-2007, Ext JS, LLC.
35313 * Originally Released Under LGPL - original licence link has changed is not relivant.
35316 * <script type="text/javascript">
35321 * @class Roo.tree.ColumnTree
35322 * @extends Roo.data.TreePanel
35323 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35324 * @cfg {int} borderWidth compined right/left border allowance
35326 * @param {String/HTMLElement/Element} el The container element
35327 * @param {Object} config
35329 Roo.tree.ColumnTree = function(el, config)
35331 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35335 * Fire this event on a container when it resizes
35336 * @param {int} w Width
35337 * @param {int} h Height
35341 this.on('resize', this.onResize, this);
35344 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35348 borderWidth: Roo.isBorderBox ? 0 : 2,
35351 render : function(){
35352 // add the header.....
35354 Roo.tree.ColumnTree.superclass.render.apply(this);
35356 this.el.addClass('x-column-tree');
35358 this.headers = this.el.createChild(
35359 {cls:'x-tree-headers'},this.innerCt.dom);
35361 var cols = this.columns, c;
35362 var totalWidth = 0;
35364 var len = cols.length;
35365 for(var i = 0; i < len; i++){
35367 totalWidth += c.width;
35368 this.headEls.push(this.headers.createChild({
35369 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35371 cls:'x-tree-hd-text',
35374 style:'width:'+(c.width-this.borderWidth)+'px;'
35377 this.headers.createChild({cls:'x-clear'});
35378 // prevent floats from wrapping when clipped
35379 this.headers.setWidth(totalWidth);
35380 //this.innerCt.setWidth(totalWidth);
35381 this.innerCt.setStyle({ overflow: 'auto' });
35382 this.onResize(this.width, this.height);
35386 onResize : function(w,h)
35391 this.innerCt.setWidth(this.width);
35392 this.innerCt.setHeight(this.height-20);
35395 var cols = this.columns, c;
35396 var totalWidth = 0;
35398 var len = cols.length;
35399 for(var i = 0; i < len; i++){
35401 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35402 // it's the expander..
35403 expEl = this.headEls[i];
35406 totalWidth += c.width;
35410 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35412 this.headers.setWidth(w-20);
35421 * Ext JS Library 1.1.1
35422 * Copyright(c) 2006-2007, Ext JS, LLC.
35424 * Originally Released Under LGPL - original licence link has changed is not relivant.
35427 * <script type="text/javascript">
35431 * @class Roo.menu.Menu
35432 * @extends Roo.util.Observable
35433 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35434 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35436 * Creates a new Menu
35437 * @param {Object} config Configuration options
35439 Roo.menu.Menu = function(config){
35440 Roo.apply(this, config);
35441 this.id = this.id || Roo.id();
35444 * @event beforeshow
35445 * Fires before this menu is displayed
35446 * @param {Roo.menu.Menu} this
35450 * @event beforehide
35451 * Fires before this menu is hidden
35452 * @param {Roo.menu.Menu} this
35457 * Fires after this menu is displayed
35458 * @param {Roo.menu.Menu} this
35463 * Fires after this menu is hidden
35464 * @param {Roo.menu.Menu} this
35469 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35470 * @param {Roo.menu.Menu} this
35471 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35472 * @param {Roo.EventObject} e
35477 * Fires when the mouse is hovering over this menu
35478 * @param {Roo.menu.Menu} this
35479 * @param {Roo.EventObject} e
35480 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35485 * Fires when the mouse exits this menu
35486 * @param {Roo.menu.Menu} this
35487 * @param {Roo.EventObject} e
35488 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35493 * Fires when a menu item contained in this menu is clicked
35494 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35495 * @param {Roo.EventObject} e
35499 if (this.registerMenu) {
35500 Roo.menu.MenuMgr.register(this);
35503 var mis = this.items;
35504 this.items = new Roo.util.MixedCollection();
35506 this.add.apply(this, mis);
35510 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35512 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35516 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35517 * for bottom-right shadow (defaults to "sides")
35521 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35522 * this menu (defaults to "tl-tr?")
35524 subMenuAlign : "tl-tr?",
35526 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35527 * relative to its element of origin (defaults to "tl-bl?")
35529 defaultAlign : "tl-bl?",
35531 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35533 allowOtherMenus : false,
35535 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35537 registerMenu : true,
35542 render : function(){
35546 var el = this.el = new Roo.Layer({
35548 shadow:this.shadow,
35550 parentEl: this.parentEl || document.body,
35554 this.keyNav = new Roo.menu.MenuNav(this);
35557 el.addClass("x-menu-plain");
35560 el.addClass(this.cls);
35562 // generic focus element
35563 this.focusEl = el.createChild({
35564 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35566 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35567 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35569 ul.on("mouseover", this.onMouseOver, this);
35570 ul.on("mouseout", this.onMouseOut, this);
35571 this.items.each(function(item){
35576 var li = document.createElement("li");
35577 li.className = "x-menu-list-item";
35578 ul.dom.appendChild(li);
35579 item.render(li, this);
35586 autoWidth : function(){
35587 var el = this.el, ul = this.ul;
35591 var w = this.width;
35594 }else if(Roo.isIE){
35595 el.setWidth(this.minWidth);
35596 var t = el.dom.offsetWidth; // force recalc
35597 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35602 delayAutoWidth : function(){
35605 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35607 this.awTask.delay(20);
35612 findTargetItem : function(e){
35613 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35614 if(t && t.menuItemId){
35615 return this.items.get(t.menuItemId);
35620 onClick : function(e){
35621 Roo.log("menu.onClick");
35622 var t = this.findTargetItem(e);
35627 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35628 if(t == this.activeItem && t.shouldDeactivate(e)){
35629 this.activeItem.deactivate();
35630 delete this.activeItem;
35634 this.setActiveItem(t, true);
35642 this.fireEvent("click", this, t, e);
35646 setActiveItem : function(item, autoExpand){
35647 if(item != this.activeItem){
35648 if(this.activeItem){
35649 this.activeItem.deactivate();
35651 this.activeItem = item;
35652 item.activate(autoExpand);
35653 }else if(autoExpand){
35659 tryActivate : function(start, step){
35660 var items = this.items;
35661 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35662 var item = items.get(i);
35663 if(!item.disabled && item.canActivate){
35664 this.setActiveItem(item, false);
35672 onMouseOver : function(e){
35674 if(t = this.findTargetItem(e)){
35675 if(t.canActivate && !t.disabled){
35676 this.setActiveItem(t, true);
35679 this.fireEvent("mouseover", this, e, t);
35683 onMouseOut : function(e){
35685 if(t = this.findTargetItem(e)){
35686 if(t == this.activeItem && t.shouldDeactivate(e)){
35687 this.activeItem.deactivate();
35688 delete this.activeItem;
35691 this.fireEvent("mouseout", this, e, t);
35695 * Read-only. Returns true if the menu is currently displayed, else false.
35698 isVisible : function(){
35699 return this.el && !this.hidden;
35703 * Displays this menu relative to another element
35704 * @param {String/HTMLElement/Roo.Element} element The element to align to
35705 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35706 * the element (defaults to this.defaultAlign)
35707 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35709 show : function(el, pos, parentMenu){
35710 this.parentMenu = parentMenu;
35714 this.fireEvent("beforeshow", this);
35715 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35719 * Displays this menu at a specific xy position
35720 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35721 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35723 showAt : function(xy, parentMenu, /* private: */_e){
35724 this.parentMenu = parentMenu;
35729 this.fireEvent("beforeshow", this);
35730 xy = this.el.adjustForConstraints(xy);
35734 this.hidden = false;
35736 this.fireEvent("show", this);
35739 focus : function(){
35741 this.doFocus.defer(50, this);
35745 doFocus : function(){
35747 this.focusEl.focus();
35752 * Hides this menu and optionally all parent menus
35753 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35755 hide : function(deep){
35756 if(this.el && this.isVisible()){
35757 this.fireEvent("beforehide", this);
35758 if(this.activeItem){
35759 this.activeItem.deactivate();
35760 this.activeItem = null;
35763 this.hidden = true;
35764 this.fireEvent("hide", this);
35766 if(deep === true && this.parentMenu){
35767 this.parentMenu.hide(true);
35772 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35773 * Any of the following are valid:
35775 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35776 * <li>An HTMLElement object which will be converted to a menu item</li>
35777 * <li>A menu item config object that will be created as a new menu item</li>
35778 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35779 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35784 var menu = new Roo.menu.Menu();
35786 // Create a menu item to add by reference
35787 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35789 // Add a bunch of items at once using different methods.
35790 // Only the last item added will be returned.
35791 var item = menu.add(
35792 menuItem, // add existing item by ref
35793 'Dynamic Item', // new TextItem
35794 '-', // new separator
35795 { text: 'Config Item' } // new item by config
35798 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35799 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35802 var a = arguments, l = a.length, item;
35803 for(var i = 0; i < l; i++){
35805 if ((typeof(el) == "object") && el.xtype && el.xns) {
35806 el = Roo.factory(el, Roo.menu);
35809 if(el.render){ // some kind of Item
35810 item = this.addItem(el);
35811 }else if(typeof el == "string"){ // string
35812 if(el == "separator" || el == "-"){
35813 item = this.addSeparator();
35815 item = this.addText(el);
35817 }else if(el.tagName || el.el){ // element
35818 item = this.addElement(el);
35819 }else if(typeof el == "object"){ // must be menu item config?
35820 item = this.addMenuItem(el);
35827 * Returns this menu's underlying {@link Roo.Element} object
35828 * @return {Roo.Element} The element
35830 getEl : function(){
35838 * Adds a separator bar to the menu
35839 * @return {Roo.menu.Item} The menu item that was added
35841 addSeparator : function(){
35842 return this.addItem(new Roo.menu.Separator());
35846 * Adds an {@link Roo.Element} object to the menu
35847 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35848 * @return {Roo.menu.Item} The menu item that was added
35850 addElement : function(el){
35851 return this.addItem(new Roo.menu.BaseItem(el));
35855 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35856 * @param {Roo.menu.Item} item The menu item to add
35857 * @return {Roo.menu.Item} The menu item that was added
35859 addItem : function(item){
35860 this.items.add(item);
35862 var li = document.createElement("li");
35863 li.className = "x-menu-list-item";
35864 this.ul.dom.appendChild(li);
35865 item.render(li, this);
35866 this.delayAutoWidth();
35872 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35873 * @param {Object} config A MenuItem config object
35874 * @return {Roo.menu.Item} The menu item that was added
35876 addMenuItem : function(config){
35877 if(!(config instanceof Roo.menu.Item)){
35878 if(typeof config.checked == "boolean"){ // must be check menu item config?
35879 config = new Roo.menu.CheckItem(config);
35881 config = new Roo.menu.Item(config);
35884 return this.addItem(config);
35888 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35889 * @param {String} text The text to display in the menu item
35890 * @return {Roo.menu.Item} The menu item that was added
35892 addText : function(text){
35893 return this.addItem(new Roo.menu.TextItem({ text : text }));
35897 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35898 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35899 * @param {Roo.menu.Item} item The menu item to add
35900 * @return {Roo.menu.Item} The menu item that was added
35902 insert : function(index, item){
35903 this.items.insert(index, item);
35905 var li = document.createElement("li");
35906 li.className = "x-menu-list-item";
35907 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35908 item.render(li, this);
35909 this.delayAutoWidth();
35915 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35916 * @param {Roo.menu.Item} item The menu item to remove
35918 remove : function(item){
35919 this.items.removeKey(item.id);
35924 * Removes and destroys all items in the menu
35926 removeAll : function(){
35928 while(f = this.items.first()){
35934 // MenuNav is a private utility class used internally by the Menu
35935 Roo.menu.MenuNav = function(menu){
35936 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35937 this.scope = this.menu = menu;
35940 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35941 doRelay : function(e, h){
35942 var k = e.getKey();
35943 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35944 this.menu.tryActivate(0, 1);
35947 return h.call(this.scope || this, e, this.menu);
35950 up : function(e, m){
35951 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35952 m.tryActivate(m.items.length-1, -1);
35956 down : function(e, m){
35957 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35958 m.tryActivate(0, 1);
35962 right : function(e, m){
35964 m.activeItem.expandMenu(true);
35968 left : function(e, m){
35970 if(m.parentMenu && m.parentMenu.activeItem){
35971 m.parentMenu.activeItem.activate();
35975 enter : function(e, m){
35977 e.stopPropagation();
35978 m.activeItem.onClick(e);
35979 m.fireEvent("click", this, m.activeItem);
35985 * Ext JS Library 1.1.1
35986 * Copyright(c) 2006-2007, Ext JS, LLC.
35988 * Originally Released Under LGPL - original licence link has changed is not relivant.
35991 * <script type="text/javascript">
35995 * @class Roo.menu.MenuMgr
35996 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35999 Roo.menu.MenuMgr = function(){
36000 var menus, active, groups = {}, attached = false, lastShow = new Date();
36002 // private - called when first menu is created
36005 active = new Roo.util.MixedCollection();
36006 Roo.get(document).addKeyListener(27, function(){
36007 if(active.length > 0){
36014 function hideAll(){
36015 if(active && active.length > 0){
36016 var c = active.clone();
36017 c.each(function(m){
36024 function onHide(m){
36026 if(active.length < 1){
36027 Roo.get(document).un("mousedown", onMouseDown);
36033 function onShow(m){
36034 var last = active.last();
36035 lastShow = new Date();
36038 Roo.get(document).on("mousedown", onMouseDown);
36042 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36043 m.parentMenu.activeChild = m;
36044 }else if(last && last.isVisible()){
36045 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36050 function onBeforeHide(m){
36052 m.activeChild.hide();
36054 if(m.autoHideTimer){
36055 clearTimeout(m.autoHideTimer);
36056 delete m.autoHideTimer;
36061 function onBeforeShow(m){
36062 var pm = m.parentMenu;
36063 if(!pm && !m.allowOtherMenus){
36065 }else if(pm && pm.activeChild && active != m){
36066 pm.activeChild.hide();
36071 function onMouseDown(e){
36072 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36078 function onBeforeCheck(mi, state){
36080 var g = groups[mi.group];
36081 for(var i = 0, l = g.length; i < l; i++){
36083 g[i].setChecked(false);
36092 * Hides all menus that are currently visible
36094 hideAll : function(){
36099 register : function(menu){
36103 menus[menu.id] = menu;
36104 menu.on("beforehide", onBeforeHide);
36105 menu.on("hide", onHide);
36106 menu.on("beforeshow", onBeforeShow);
36107 menu.on("show", onShow);
36108 var g = menu.group;
36109 if(g && menu.events["checkchange"]){
36113 groups[g].push(menu);
36114 menu.on("checkchange", onCheck);
36119 * Returns a {@link Roo.menu.Menu} object
36120 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36121 * be used to generate and return a new Menu instance.
36123 get : function(menu){
36124 if(typeof menu == "string"){ // menu id
36125 return menus[menu];
36126 }else if(menu.events){ // menu instance
36128 }else if(typeof menu.length == 'number'){ // array of menu items?
36129 return new Roo.menu.Menu({items:menu});
36130 }else{ // otherwise, must be a config
36131 return new Roo.menu.Menu(menu);
36136 unregister : function(menu){
36137 delete menus[menu.id];
36138 menu.un("beforehide", onBeforeHide);
36139 menu.un("hide", onHide);
36140 menu.un("beforeshow", onBeforeShow);
36141 menu.un("show", onShow);
36142 var g = menu.group;
36143 if(g && menu.events["checkchange"]){
36144 groups[g].remove(menu);
36145 menu.un("checkchange", onCheck);
36150 registerCheckable : function(menuItem){
36151 var g = menuItem.group;
36156 groups[g].push(menuItem);
36157 menuItem.on("beforecheckchange", onBeforeCheck);
36162 unregisterCheckable : function(menuItem){
36163 var g = menuItem.group;
36165 groups[g].remove(menuItem);
36166 menuItem.un("beforecheckchange", onBeforeCheck);
36172 * Ext JS Library 1.1.1
36173 * Copyright(c) 2006-2007, Ext JS, LLC.
36175 * Originally Released Under LGPL - original licence link has changed is not relivant.
36178 * <script type="text/javascript">
36183 * @class Roo.menu.BaseItem
36184 * @extends Roo.Component
36185 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36186 * management and base configuration options shared by all menu components.
36188 * Creates a new BaseItem
36189 * @param {Object} config Configuration options
36191 Roo.menu.BaseItem = function(config){
36192 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36197 * Fires when this item is clicked
36198 * @param {Roo.menu.BaseItem} this
36199 * @param {Roo.EventObject} e
36204 * Fires when this item is activated
36205 * @param {Roo.menu.BaseItem} this
36209 * @event deactivate
36210 * Fires when this item is deactivated
36211 * @param {Roo.menu.BaseItem} this
36217 this.on("click", this.handler, this.scope, true);
36221 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36223 * @cfg {Function} handler
36224 * A function that will handle the click event of this menu item (defaults to undefined)
36227 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36229 canActivate : false,
36232 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36237 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36239 activeClass : "x-menu-item-active",
36241 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36243 hideOnClick : true,
36245 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36250 ctype: "Roo.menu.BaseItem",
36253 actionMode : "container",
36256 render : function(container, parentMenu){
36257 this.parentMenu = parentMenu;
36258 Roo.menu.BaseItem.superclass.render.call(this, container);
36259 this.container.menuItemId = this.id;
36263 onRender : function(container, position){
36264 this.el = Roo.get(this.el);
36265 container.dom.appendChild(this.el.dom);
36269 onClick : function(e){
36270 if(!this.disabled && this.fireEvent("click", this, e) !== false
36271 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36272 this.handleClick(e);
36279 activate : function(){
36283 var li = this.container;
36284 li.addClass(this.activeClass);
36285 this.region = li.getRegion().adjust(2, 2, -2, -2);
36286 this.fireEvent("activate", this);
36291 deactivate : function(){
36292 this.container.removeClass(this.activeClass);
36293 this.fireEvent("deactivate", this);
36297 shouldDeactivate : function(e){
36298 return !this.region || !this.region.contains(e.getPoint());
36302 handleClick : function(e){
36303 if(this.hideOnClick){
36304 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36309 expandMenu : function(autoActivate){
36314 hideMenu : function(){
36319 * Ext JS Library 1.1.1
36320 * Copyright(c) 2006-2007, Ext JS, LLC.
36322 * Originally Released Under LGPL - original licence link has changed is not relivant.
36325 * <script type="text/javascript">
36329 * @class Roo.menu.Adapter
36330 * @extends Roo.menu.BaseItem
36331 * 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.
36332 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36334 * Creates a new Adapter
36335 * @param {Object} config Configuration options
36337 Roo.menu.Adapter = function(component, config){
36338 Roo.menu.Adapter.superclass.constructor.call(this, config);
36339 this.component = component;
36341 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36343 canActivate : true,
36346 onRender : function(container, position){
36347 this.component.render(container);
36348 this.el = this.component.getEl();
36352 activate : function(){
36356 this.component.focus();
36357 this.fireEvent("activate", this);
36362 deactivate : function(){
36363 this.fireEvent("deactivate", this);
36367 disable : function(){
36368 this.component.disable();
36369 Roo.menu.Adapter.superclass.disable.call(this);
36373 enable : function(){
36374 this.component.enable();
36375 Roo.menu.Adapter.superclass.enable.call(this);
36379 * Ext JS Library 1.1.1
36380 * Copyright(c) 2006-2007, Ext JS, LLC.
36382 * Originally Released Under LGPL - original licence link has changed is not relivant.
36385 * <script type="text/javascript">
36389 * @class Roo.menu.TextItem
36390 * @extends Roo.menu.BaseItem
36391 * Adds a static text string to a menu, usually used as either a heading or group separator.
36392 * Note: old style constructor with text is still supported.
36395 * Creates a new TextItem
36396 * @param {Object} cfg Configuration
36398 Roo.menu.TextItem = function(cfg){
36399 if (typeof(cfg) == 'string') {
36402 Roo.apply(this,cfg);
36405 Roo.menu.TextItem.superclass.constructor.call(this);
36408 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36410 * @cfg {Boolean} text Text to show on item.
36415 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36417 hideOnClick : false,
36419 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36421 itemCls : "x-menu-text",
36424 onRender : function(){
36425 var s = document.createElement("span");
36426 s.className = this.itemCls;
36427 s.innerHTML = this.text;
36429 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36433 * Ext JS Library 1.1.1
36434 * Copyright(c) 2006-2007, Ext JS, LLC.
36436 * Originally Released Under LGPL - original licence link has changed is not relivant.
36439 * <script type="text/javascript">
36443 * @class Roo.menu.Separator
36444 * @extends Roo.menu.BaseItem
36445 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36446 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36448 * @param {Object} config Configuration options
36450 Roo.menu.Separator = function(config){
36451 Roo.menu.Separator.superclass.constructor.call(this, config);
36454 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36456 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36458 itemCls : "x-menu-sep",
36460 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36462 hideOnClick : false,
36465 onRender : function(li){
36466 var s = document.createElement("span");
36467 s.className = this.itemCls;
36468 s.innerHTML = " ";
36470 li.addClass("x-menu-sep-li");
36471 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36475 * Ext JS Library 1.1.1
36476 * Copyright(c) 2006-2007, Ext JS, LLC.
36478 * Originally Released Under LGPL - original licence link has changed is not relivant.
36481 * <script type="text/javascript">
36484 * @class Roo.menu.Item
36485 * @extends Roo.menu.BaseItem
36486 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36487 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36488 * activation and click handling.
36490 * Creates a new Item
36491 * @param {Object} config Configuration options
36493 Roo.menu.Item = function(config){
36494 Roo.menu.Item.superclass.constructor.call(this, config);
36496 this.menu = Roo.menu.MenuMgr.get(this.menu);
36499 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36502 * @cfg {String} text
36503 * The text to show on the menu item.
36507 * @cfg {String} HTML to render in menu
36508 * The text to show on the menu item (HTML version).
36512 * @cfg {String} icon
36513 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36517 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36519 itemCls : "x-menu-item",
36521 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36523 canActivate : true,
36525 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36528 // doc'd in BaseItem
36532 ctype: "Roo.menu.Item",
36535 onRender : function(container, position){
36536 var el = document.createElement("a");
36537 el.hideFocus = true;
36538 el.unselectable = "on";
36539 el.href = this.href || "#";
36540 if(this.hrefTarget){
36541 el.target = this.hrefTarget;
36543 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36545 var html = this.html.length ? this.html : String.format('{0}',this.text);
36547 el.innerHTML = String.format(
36548 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36549 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36551 Roo.menu.Item.superclass.onRender.call(this, container, position);
36555 * Sets the text to display in this menu item
36556 * @param {String} text The text to display
36557 * @param {Boolean} isHTML true to indicate text is pure html.
36559 setText : function(text, isHTML){
36567 var html = this.html.length ? this.html : String.format('{0}',this.text);
36569 this.el.update(String.format(
36570 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36571 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36572 this.parentMenu.autoWidth();
36577 handleClick : function(e){
36578 if(!this.href){ // if no link defined, stop the event automatically
36581 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36585 activate : function(autoExpand){
36586 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36596 shouldDeactivate : function(e){
36597 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36598 if(this.menu && this.menu.isVisible()){
36599 return !this.menu.getEl().getRegion().contains(e.getPoint());
36607 deactivate : function(){
36608 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36613 expandMenu : function(autoActivate){
36614 if(!this.disabled && this.menu){
36615 clearTimeout(this.hideTimer);
36616 delete this.hideTimer;
36617 if(!this.menu.isVisible() && !this.showTimer){
36618 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36619 }else if (this.menu.isVisible() && autoActivate){
36620 this.menu.tryActivate(0, 1);
36626 deferExpand : function(autoActivate){
36627 delete this.showTimer;
36628 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36630 this.menu.tryActivate(0, 1);
36635 hideMenu : function(){
36636 clearTimeout(this.showTimer);
36637 delete this.showTimer;
36638 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36639 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36644 deferHide : function(){
36645 delete this.hideTimer;
36650 * Ext JS Library 1.1.1
36651 * Copyright(c) 2006-2007, Ext JS, LLC.
36653 * Originally Released Under LGPL - original licence link has changed is not relivant.
36656 * <script type="text/javascript">
36660 * @class Roo.menu.CheckItem
36661 * @extends Roo.menu.Item
36662 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36664 * Creates a new CheckItem
36665 * @param {Object} config Configuration options
36667 Roo.menu.CheckItem = function(config){
36668 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36671 * @event beforecheckchange
36672 * Fires before the checked value is set, providing an opportunity to cancel if needed
36673 * @param {Roo.menu.CheckItem} this
36674 * @param {Boolean} checked The new checked value that will be set
36676 "beforecheckchange" : true,
36678 * @event checkchange
36679 * Fires after the checked value has been set
36680 * @param {Roo.menu.CheckItem} this
36681 * @param {Boolean} checked The checked value that was set
36683 "checkchange" : true
36685 if(this.checkHandler){
36686 this.on('checkchange', this.checkHandler, this.scope);
36689 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36691 * @cfg {String} group
36692 * All check items with the same group name will automatically be grouped into a single-select
36693 * radio button group (defaults to '')
36696 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36698 itemCls : "x-menu-item x-menu-check-item",
36700 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36702 groupClass : "x-menu-group-item",
36705 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36706 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36707 * initialized with checked = true will be rendered as checked.
36712 ctype: "Roo.menu.CheckItem",
36715 onRender : function(c){
36716 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36718 this.el.addClass(this.groupClass);
36720 Roo.menu.MenuMgr.registerCheckable(this);
36722 this.checked = false;
36723 this.setChecked(true, true);
36728 destroy : function(){
36730 Roo.menu.MenuMgr.unregisterCheckable(this);
36732 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36736 * Set the checked state of this item
36737 * @param {Boolean} checked The new checked value
36738 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36740 setChecked : function(state, suppressEvent){
36741 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36742 if(this.container){
36743 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36745 this.checked = state;
36746 if(suppressEvent !== true){
36747 this.fireEvent("checkchange", this, state);
36753 handleClick : function(e){
36754 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36755 this.setChecked(!this.checked);
36757 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36761 * Ext JS Library 1.1.1
36762 * Copyright(c) 2006-2007, Ext JS, LLC.
36764 * Originally Released Under LGPL - original licence link has changed is not relivant.
36767 * <script type="text/javascript">
36771 * @class Roo.menu.DateItem
36772 * @extends Roo.menu.Adapter
36773 * A menu item that wraps the {@link Roo.DatPicker} component.
36775 * Creates a new DateItem
36776 * @param {Object} config Configuration options
36778 Roo.menu.DateItem = function(config){
36779 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36780 /** The Roo.DatePicker object @type Roo.DatePicker */
36781 this.picker = this.component;
36782 this.addEvents({select: true});
36784 this.picker.on("render", function(picker){
36785 picker.getEl().swallowEvent("click");
36786 picker.container.addClass("x-menu-date-item");
36789 this.picker.on("select", this.onSelect, this);
36792 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36794 onSelect : function(picker, date){
36795 this.fireEvent("select", this, date, picker);
36796 Roo.menu.DateItem.superclass.handleClick.call(this);
36800 * Ext JS Library 1.1.1
36801 * Copyright(c) 2006-2007, Ext JS, LLC.
36803 * Originally Released Under LGPL - original licence link has changed is not relivant.
36806 * <script type="text/javascript">
36810 * @class Roo.menu.ColorItem
36811 * @extends Roo.menu.Adapter
36812 * A menu item that wraps the {@link Roo.ColorPalette} component.
36814 * Creates a new ColorItem
36815 * @param {Object} config Configuration options
36817 Roo.menu.ColorItem = function(config){
36818 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36819 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36820 this.palette = this.component;
36821 this.relayEvents(this.palette, ["select"]);
36822 if(this.selectHandler){
36823 this.on('select', this.selectHandler, this.scope);
36826 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36828 * Ext JS Library 1.1.1
36829 * Copyright(c) 2006-2007, Ext JS, LLC.
36831 * Originally Released Under LGPL - original licence link has changed is not relivant.
36834 * <script type="text/javascript">
36839 * @class Roo.menu.DateMenu
36840 * @extends Roo.menu.Menu
36841 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36843 * Creates a new DateMenu
36844 * @param {Object} config Configuration options
36846 Roo.menu.DateMenu = function(config){
36847 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36849 var di = new Roo.menu.DateItem(config);
36852 * The {@link Roo.DatePicker} instance for this DateMenu
36855 this.picker = di.picker;
36858 * @param {DatePicker} picker
36859 * @param {Date} date
36861 this.relayEvents(di, ["select"]);
36862 this.on('beforeshow', function(){
36864 this.picker.hideMonthPicker(false);
36868 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36872 * Ext JS Library 1.1.1
36873 * Copyright(c) 2006-2007, Ext JS, LLC.
36875 * Originally Released Under LGPL - original licence link has changed is not relivant.
36878 * <script type="text/javascript">
36883 * @class Roo.menu.ColorMenu
36884 * @extends Roo.menu.Menu
36885 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36887 * Creates a new ColorMenu
36888 * @param {Object} config Configuration options
36890 Roo.menu.ColorMenu = function(config){
36891 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36893 var ci = new Roo.menu.ColorItem(config);
36896 * The {@link Roo.ColorPalette} instance for this ColorMenu
36897 * @type ColorPalette
36899 this.palette = ci.palette;
36902 * @param {ColorPalette} palette
36903 * @param {String} color
36905 this.relayEvents(ci, ["select"]);
36907 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36909 * Ext JS Library 1.1.1
36910 * Copyright(c) 2006-2007, Ext JS, LLC.
36912 * Originally Released Under LGPL - original licence link has changed is not relivant.
36915 * <script type="text/javascript">
36919 * @class Roo.form.Field
36920 * @extends Roo.BoxComponent
36921 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36923 * Creates a new Field
36924 * @param {Object} config Configuration options
36926 Roo.form.Field = function(config){
36927 Roo.form.Field.superclass.constructor.call(this, config);
36930 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36932 * @cfg {String} fieldLabel Label to use when rendering a form.
36935 * @cfg {String} qtip Mouse over tip
36939 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36941 invalidClass : "x-form-invalid",
36943 * @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")
36945 invalidText : "The value in this field is invalid",
36947 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36949 focusClass : "x-form-focus",
36951 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36952 automatic validation (defaults to "keyup").
36954 validationEvent : "keyup",
36956 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36958 validateOnBlur : true,
36960 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36962 validationDelay : 250,
36964 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36965 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36967 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36969 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36971 fieldClass : "x-form-field",
36973 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36976 ----------- ----------------------------------------------------------------------
36977 qtip Display a quick tip when the user hovers over the field
36978 title Display a default browser title attribute popup
36979 under Add a block div beneath the field containing the error text
36980 side Add an error icon to the right of the field with a popup on hover
36981 [element id] Add the error text directly to the innerHTML of the specified element
36984 msgTarget : 'qtip',
36986 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36991 * @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.
36996 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37001 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37003 inputType : undefined,
37006 * @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).
37008 tabIndex : undefined,
37011 isFormField : true,
37016 * @property {Roo.Element} fieldEl
37017 * Element Containing the rendered Field (with label etc.)
37020 * @cfg {Mixed} value A value to initialize this field with.
37025 * @cfg {String} name The field's HTML name attribute.
37028 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37032 initComponent : function(){
37033 Roo.form.Field.superclass.initComponent.call(this);
37037 * Fires when this field receives input focus.
37038 * @param {Roo.form.Field} this
37043 * Fires when this field loses input focus.
37044 * @param {Roo.form.Field} this
37048 * @event specialkey
37049 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37050 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37051 * @param {Roo.form.Field} this
37052 * @param {Roo.EventObject} e The event object
37057 * Fires just before the field blurs if the field value has changed.
37058 * @param {Roo.form.Field} this
37059 * @param {Mixed} newValue The new value
37060 * @param {Mixed} oldValue The original value
37065 * Fires after the field has been marked as invalid.
37066 * @param {Roo.form.Field} this
37067 * @param {String} msg The validation message
37072 * Fires after the field has been validated with no errors.
37073 * @param {Roo.form.Field} this
37078 * Fires after the key up
37079 * @param {Roo.form.Field} this
37080 * @param {Roo.EventObject} e The event Object
37087 * Returns the name attribute of the field if available
37088 * @return {String} name The field name
37090 getName: function(){
37091 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37095 onRender : function(ct, position){
37096 Roo.form.Field.superclass.onRender.call(this, ct, position);
37098 var cfg = this.getAutoCreate();
37100 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37102 if (!cfg.name.length) {
37105 if(this.inputType){
37106 cfg.type = this.inputType;
37108 this.el = ct.createChild(cfg, position);
37110 var type = this.el.dom.type;
37112 if(type == 'password'){
37115 this.el.addClass('x-form-'+type);
37118 this.el.dom.readOnly = true;
37120 if(this.tabIndex !== undefined){
37121 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37124 this.el.addClass([this.fieldClass, this.cls]);
37129 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37130 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37131 * @return {Roo.form.Field} this
37133 applyTo : function(target){
37134 this.allowDomMove = false;
37135 this.el = Roo.get(target);
37136 this.render(this.el.dom.parentNode);
37141 initValue : function(){
37142 if(this.value !== undefined){
37143 this.setValue(this.value);
37144 }else if(this.el.dom.value.length > 0){
37145 this.setValue(this.el.dom.value);
37150 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37152 isDirty : function() {
37153 if(this.disabled) {
37156 return String(this.getValue()) !== String(this.originalValue);
37160 afterRender : function(){
37161 Roo.form.Field.superclass.afterRender.call(this);
37166 fireKey : function(e){
37167 //Roo.log('field ' + e.getKey());
37168 if(e.isNavKeyPress()){
37169 this.fireEvent("specialkey", this, e);
37174 * Resets the current field value to the originally loaded value and clears any validation messages
37176 reset : function(){
37177 this.setValue(this.resetValue);
37178 this.clearInvalid();
37182 initEvents : function(){
37183 // safari killled keypress - so keydown is now used..
37184 this.el.on("keydown" , this.fireKey, this);
37185 this.el.on("focus", this.onFocus, this);
37186 this.el.on("blur", this.onBlur, this);
37187 this.el.relayEvent('keyup', this);
37189 // reference to original value for reset
37190 this.originalValue = this.getValue();
37191 this.resetValue = this.getValue();
37195 onFocus : function(){
37196 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37197 this.el.addClass(this.focusClass);
37199 if(!this.hasFocus){
37200 this.hasFocus = true;
37201 this.startValue = this.getValue();
37202 this.fireEvent("focus", this);
37206 beforeBlur : Roo.emptyFn,
37209 onBlur : function(){
37211 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37212 this.el.removeClass(this.focusClass);
37214 this.hasFocus = false;
37215 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37218 var v = this.getValue();
37219 if(String(v) !== String(this.startValue)){
37220 this.fireEvent('change', this, v, this.startValue);
37222 this.fireEvent("blur", this);
37226 * Returns whether or not the field value is currently valid
37227 * @param {Boolean} preventMark True to disable marking the field invalid
37228 * @return {Boolean} True if the value is valid, else false
37230 isValid : function(preventMark){
37234 var restore = this.preventMark;
37235 this.preventMark = preventMark === true;
37236 var v = this.validateValue(this.processValue(this.getRawValue()));
37237 this.preventMark = restore;
37242 * Validates the field value
37243 * @return {Boolean} True if the value is valid, else false
37245 validate : function(){
37246 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37247 this.clearInvalid();
37253 processValue : function(value){
37258 // Subclasses should provide the validation implementation by overriding this
37259 validateValue : function(value){
37264 * Mark this field as invalid
37265 * @param {String} msg The validation message
37267 markInvalid : function(msg){
37268 if(!this.rendered || this.preventMark){ // not rendered
37272 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37274 obj.el.addClass(this.invalidClass);
37275 msg = msg || this.invalidText;
37276 switch(this.msgTarget){
37278 obj.el.dom.qtip = msg;
37279 obj.el.dom.qclass = 'x-form-invalid-tip';
37280 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37281 Roo.QuickTips.enable();
37285 this.el.dom.title = msg;
37289 var elp = this.el.findParent('.x-form-element', 5, true);
37290 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37291 this.errorEl.setWidth(elp.getWidth(true)-20);
37293 this.errorEl.update(msg);
37294 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37297 if(!this.errorIcon){
37298 var elp = this.el.findParent('.x-form-element', 5, true);
37299 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37301 this.alignErrorIcon();
37302 this.errorIcon.dom.qtip = msg;
37303 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37304 this.errorIcon.show();
37305 this.on('resize', this.alignErrorIcon, this);
37308 var t = Roo.getDom(this.msgTarget);
37310 t.style.display = this.msgDisplay;
37313 this.fireEvent('invalid', this, msg);
37317 alignErrorIcon : function(){
37318 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37322 * Clear any invalid styles/messages for this field
37324 clearInvalid : function(){
37325 if(!this.rendered || this.preventMark){ // not rendered
37328 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37330 obj.el.removeClass(this.invalidClass);
37331 switch(this.msgTarget){
37333 obj.el.dom.qtip = '';
37336 this.el.dom.title = '';
37340 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37344 if(this.errorIcon){
37345 this.errorIcon.dom.qtip = '';
37346 this.errorIcon.hide();
37347 this.un('resize', this.alignErrorIcon, this);
37351 var t = Roo.getDom(this.msgTarget);
37353 t.style.display = 'none';
37356 this.fireEvent('valid', this);
37360 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37361 * @return {Mixed} value The field value
37363 getRawValue : function(){
37364 var v = this.el.getValue();
37370 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37371 * @return {Mixed} value The field value
37373 getValue : function(){
37374 var v = this.el.getValue();
37380 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37381 * @param {Mixed} value The value to set
37383 setRawValue : function(v){
37384 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37388 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37389 * @param {Mixed} value The value to set
37391 setValue : function(v){
37394 this.el.dom.value = (v === null || v === undefined ? '' : v);
37399 adjustSize : function(w, h){
37400 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37401 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37405 adjustWidth : function(tag, w){
37406 tag = tag.toLowerCase();
37407 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37408 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37409 if(tag == 'input'){
37412 if(tag == 'textarea'){
37415 }else if(Roo.isOpera){
37416 if(tag == 'input'){
37419 if(tag == 'textarea'){
37429 // anything other than normal should be considered experimental
37430 Roo.form.Field.msgFx = {
37432 show: function(msgEl, f){
37433 msgEl.setDisplayed('block');
37436 hide : function(msgEl, f){
37437 msgEl.setDisplayed(false).update('');
37442 show: function(msgEl, f){
37443 msgEl.slideIn('t', {stopFx:true});
37446 hide : function(msgEl, f){
37447 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37452 show: function(msgEl, f){
37453 msgEl.fixDisplay();
37454 msgEl.alignTo(f.el, 'tl-tr');
37455 msgEl.slideIn('l', {stopFx:true});
37458 hide : function(msgEl, f){
37459 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37464 * Ext JS Library 1.1.1
37465 * Copyright(c) 2006-2007, Ext JS, LLC.
37467 * Originally Released Under LGPL - original licence link has changed is not relivant.
37470 * <script type="text/javascript">
37475 * @class Roo.form.TextField
37476 * @extends Roo.form.Field
37477 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37478 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37480 * Creates a new TextField
37481 * @param {Object} config Configuration options
37483 Roo.form.TextField = function(config){
37484 Roo.form.TextField.superclass.constructor.call(this, config);
37488 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37489 * according to the default logic, but this event provides a hook for the developer to apply additional
37490 * logic at runtime to resize the field if needed.
37491 * @param {Roo.form.Field} this This text field
37492 * @param {Number} width The new field width
37498 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37500 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37504 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37508 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37512 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37516 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37520 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37522 disableKeyFilter : false,
37524 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37528 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37532 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37534 maxLength : Number.MAX_VALUE,
37536 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37538 minLengthText : "The minimum length for this field is {0}",
37540 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37542 maxLengthText : "The maximum length for this field is {0}",
37544 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37546 selectOnFocus : false,
37548 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37550 blankText : "This field is required",
37552 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37553 * If available, this function will be called only after the basic validators all return true, and will be passed the
37554 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37558 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37559 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37560 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37564 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37568 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37574 initEvents : function()
37576 if (this.emptyText) {
37577 this.el.attr('placeholder', this.emptyText);
37580 Roo.form.TextField.superclass.initEvents.call(this);
37581 if(this.validationEvent == 'keyup'){
37582 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37583 this.el.on('keyup', this.filterValidation, this);
37585 else if(this.validationEvent !== false){
37586 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37589 if(this.selectOnFocus){
37590 this.on("focus", this.preFocus, this);
37593 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37594 this.el.on("keypress", this.filterKeys, this);
37597 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37598 this.el.on("click", this.autoSize, this);
37600 if(this.el.is('input[type=password]') && Roo.isSafari){
37601 this.el.on('keydown', this.SafariOnKeyDown, this);
37605 processValue : function(value){
37606 if(this.stripCharsRe){
37607 var newValue = value.replace(this.stripCharsRe, '');
37608 if(newValue !== value){
37609 this.setRawValue(newValue);
37616 filterValidation : function(e){
37617 if(!e.isNavKeyPress()){
37618 this.validationTask.delay(this.validationDelay);
37623 onKeyUp : function(e){
37624 if(!e.isNavKeyPress()){
37630 * Resets the current field value to the originally-loaded value and clears any validation messages.
37633 reset : function(){
37634 Roo.form.TextField.superclass.reset.call(this);
37640 preFocus : function(){
37642 if(this.selectOnFocus){
37643 this.el.dom.select();
37649 filterKeys : function(e){
37650 var k = e.getKey();
37651 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37654 var c = e.getCharCode(), cc = String.fromCharCode(c);
37655 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37658 if(!this.maskRe.test(cc)){
37663 setValue : function(v){
37665 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37671 * Validates a value according to the field's validation rules and marks the field as invalid
37672 * if the validation fails
37673 * @param {Mixed} value The value to validate
37674 * @return {Boolean} True if the value is valid, else false
37676 validateValue : function(value){
37677 if(value.length < 1) { // if it's blank
37678 if(this.allowBlank){
37679 this.clearInvalid();
37682 this.markInvalid(this.blankText);
37686 if(value.length < this.minLength){
37687 this.markInvalid(String.format(this.minLengthText, this.minLength));
37690 if(value.length > this.maxLength){
37691 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37695 var vt = Roo.form.VTypes;
37696 if(!vt[this.vtype](value, this)){
37697 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37701 if(typeof this.validator == "function"){
37702 var msg = this.validator(value);
37704 this.markInvalid(msg);
37708 if(this.regex && !this.regex.test(value)){
37709 this.markInvalid(this.regexText);
37716 * Selects text in this field
37717 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37718 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37720 selectText : function(start, end){
37721 var v = this.getRawValue();
37723 start = start === undefined ? 0 : start;
37724 end = end === undefined ? v.length : end;
37725 var d = this.el.dom;
37726 if(d.setSelectionRange){
37727 d.setSelectionRange(start, end);
37728 }else if(d.createTextRange){
37729 var range = d.createTextRange();
37730 range.moveStart("character", start);
37731 range.moveEnd("character", v.length-end);
37738 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37739 * This only takes effect if grow = true, and fires the autosize event.
37741 autoSize : function(){
37742 if(!this.grow || !this.rendered){
37746 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37749 var v = el.dom.value;
37750 var d = document.createElement('div');
37751 d.appendChild(document.createTextNode(v));
37755 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37756 this.el.setWidth(w);
37757 this.fireEvent("autosize", this, w);
37761 SafariOnKeyDown : function(event)
37763 // this is a workaround for a password hang bug on chrome/ webkit.
37765 var isSelectAll = false;
37767 if(this.el.dom.selectionEnd > 0){
37768 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37770 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37771 event.preventDefault();
37776 if(isSelectAll){ // backspace and delete key
37778 event.preventDefault();
37779 // this is very hacky as keydown always get's upper case.
37781 var cc = String.fromCharCode(event.getCharCode());
37782 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37790 * Ext JS Library 1.1.1
37791 * Copyright(c) 2006-2007, Ext JS, LLC.
37793 * Originally Released Under LGPL - original licence link has changed is not relivant.
37796 * <script type="text/javascript">
37800 * @class Roo.form.Hidden
37801 * @extends Roo.form.TextField
37802 * Simple Hidden element used on forms
37804 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37807 * Creates a new Hidden form element.
37808 * @param {Object} config Configuration options
37813 // easy hidden field...
37814 Roo.form.Hidden = function(config){
37815 Roo.form.Hidden.superclass.constructor.call(this, config);
37818 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37820 inputType: 'hidden',
37823 labelSeparator: '',
37825 itemCls : 'x-form-item-display-none'
37833 * Ext JS Library 1.1.1
37834 * Copyright(c) 2006-2007, Ext JS, LLC.
37836 * Originally Released Under LGPL - original licence link has changed is not relivant.
37839 * <script type="text/javascript">
37843 * @class Roo.form.TriggerField
37844 * @extends Roo.form.TextField
37845 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37846 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37847 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37848 * for which you can provide a custom implementation. For example:
37850 var trigger = new Roo.form.TriggerField();
37851 trigger.onTriggerClick = myTriggerFn;
37852 trigger.applyTo('my-field');
37855 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37856 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37857 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37858 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37860 * Create a new TriggerField.
37861 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37862 * to the base TextField)
37864 Roo.form.TriggerField = function(config){
37865 this.mimicing = false;
37866 Roo.form.TriggerField.superclass.constructor.call(this, config);
37869 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37871 * @cfg {String} triggerClass A CSS class to apply to the trigger
37874 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37875 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37877 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37879 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37883 /** @cfg {Boolean} grow @hide */
37884 /** @cfg {Number} growMin @hide */
37885 /** @cfg {Number} growMax @hide */
37891 autoSize: Roo.emptyFn,
37895 deferHeight : true,
37898 actionMode : 'wrap',
37900 onResize : function(w, h){
37901 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37902 if(typeof w == 'number'){
37903 var x = w - this.trigger.getWidth();
37904 this.el.setWidth(this.adjustWidth('input', x));
37905 this.trigger.setStyle('left', x+'px');
37910 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37913 getResizeEl : function(){
37918 getPositionEl : function(){
37923 alignErrorIcon : function(){
37924 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37928 onRender : function(ct, position){
37929 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37930 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37931 this.trigger = this.wrap.createChild(this.triggerConfig ||
37932 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37933 if(this.hideTrigger){
37934 this.trigger.setDisplayed(false);
37936 this.initTrigger();
37938 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37943 initTrigger : function(){
37944 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37945 this.trigger.addClassOnOver('x-form-trigger-over');
37946 this.trigger.addClassOnClick('x-form-trigger-click');
37950 onDestroy : function(){
37952 this.trigger.removeAllListeners();
37953 this.trigger.remove();
37956 this.wrap.remove();
37958 Roo.form.TriggerField.superclass.onDestroy.call(this);
37962 onFocus : function(){
37963 Roo.form.TriggerField.superclass.onFocus.call(this);
37964 if(!this.mimicing){
37965 this.wrap.addClass('x-trigger-wrap-focus');
37966 this.mimicing = true;
37967 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37968 if(this.monitorTab){
37969 this.el.on("keydown", this.checkTab, this);
37975 checkTab : function(e){
37976 if(e.getKey() == e.TAB){
37977 this.triggerBlur();
37982 onBlur : function(){
37987 mimicBlur : function(e, t){
37988 if(!this.wrap.contains(t) && this.validateBlur()){
37989 this.triggerBlur();
37994 triggerBlur : function(){
37995 this.mimicing = false;
37996 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37997 if(this.monitorTab){
37998 this.el.un("keydown", this.checkTab, this);
38000 this.wrap.removeClass('x-trigger-wrap-focus');
38001 Roo.form.TriggerField.superclass.onBlur.call(this);
38005 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38006 validateBlur : function(e, t){
38011 onDisable : function(){
38012 Roo.form.TriggerField.superclass.onDisable.call(this);
38014 this.wrap.addClass('x-item-disabled');
38019 onEnable : function(){
38020 Roo.form.TriggerField.superclass.onEnable.call(this);
38022 this.wrap.removeClass('x-item-disabled');
38027 onShow : function(){
38028 var ae = this.getActionEl();
38031 ae.dom.style.display = '';
38032 ae.dom.style.visibility = 'visible';
38038 onHide : function(){
38039 var ae = this.getActionEl();
38040 ae.dom.style.display = 'none';
38044 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38045 * by an implementing function.
38047 * @param {EventObject} e
38049 onTriggerClick : Roo.emptyFn
38052 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38053 // to be extended by an implementing class. For an example of implementing this class, see the custom
38054 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38055 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38056 initComponent : function(){
38057 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38059 this.triggerConfig = {
38060 tag:'span', cls:'x-form-twin-triggers', cn:[
38061 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38062 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38066 getTrigger : function(index){
38067 return this.triggers[index];
38070 initTrigger : function(){
38071 var ts = this.trigger.select('.x-form-trigger', true);
38072 this.wrap.setStyle('overflow', 'hidden');
38073 var triggerField = this;
38074 ts.each(function(t, all, index){
38075 t.hide = function(){
38076 var w = triggerField.wrap.getWidth();
38077 this.dom.style.display = 'none';
38078 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38080 t.show = function(){
38081 var w = triggerField.wrap.getWidth();
38082 this.dom.style.display = '';
38083 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38085 var triggerIndex = 'Trigger'+(index+1);
38087 if(this['hide'+triggerIndex]){
38088 t.dom.style.display = 'none';
38090 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38091 t.addClassOnOver('x-form-trigger-over');
38092 t.addClassOnClick('x-form-trigger-click');
38094 this.triggers = ts.elements;
38097 onTrigger1Click : Roo.emptyFn,
38098 onTrigger2Click : Roo.emptyFn
38101 * Ext JS Library 1.1.1
38102 * Copyright(c) 2006-2007, Ext JS, LLC.
38104 * Originally Released Under LGPL - original licence link has changed is not relivant.
38107 * <script type="text/javascript">
38111 * @class Roo.form.TextArea
38112 * @extends Roo.form.TextField
38113 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38114 * support for auto-sizing.
38116 * Creates a new TextArea
38117 * @param {Object} config Configuration options
38119 Roo.form.TextArea = function(config){
38120 Roo.form.TextArea.superclass.constructor.call(this, config);
38121 // these are provided exchanges for backwards compat
38122 // minHeight/maxHeight were replaced by growMin/growMax to be
38123 // compatible with TextField growing config values
38124 if(this.minHeight !== undefined){
38125 this.growMin = this.minHeight;
38127 if(this.maxHeight !== undefined){
38128 this.growMax = this.maxHeight;
38132 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38134 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38138 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38142 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38143 * in the field (equivalent to setting overflow: hidden, defaults to false)
38145 preventScrollbars: false,
38147 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38148 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38152 onRender : function(ct, position){
38154 this.defaultAutoCreate = {
38156 style:"width:300px;height:60px;",
38157 autocomplete: "off"
38160 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38162 this.textSizeEl = Roo.DomHelper.append(document.body, {
38163 tag: "pre", cls: "x-form-grow-sizer"
38165 if(this.preventScrollbars){
38166 this.el.setStyle("overflow", "hidden");
38168 this.el.setHeight(this.growMin);
38172 onDestroy : function(){
38173 if(this.textSizeEl){
38174 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38176 Roo.form.TextArea.superclass.onDestroy.call(this);
38180 onKeyUp : function(e){
38181 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38187 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38188 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38190 autoSize : function(){
38191 if(!this.grow || !this.textSizeEl){
38195 var v = el.dom.value;
38196 var ts = this.textSizeEl;
38199 ts.appendChild(document.createTextNode(v));
38202 Roo.fly(ts).setWidth(this.el.getWidth());
38204 v = "  ";
38207 v = v.replace(/\n/g, '<p> </p>');
38209 v += " \n ";
38212 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38213 if(h != this.lastHeight){
38214 this.lastHeight = h;
38215 this.el.setHeight(h);
38216 this.fireEvent("autosize", this, h);
38221 * Ext JS Library 1.1.1
38222 * Copyright(c) 2006-2007, Ext JS, LLC.
38224 * Originally Released Under LGPL - original licence link has changed is not relivant.
38227 * <script type="text/javascript">
38232 * @class Roo.form.NumberField
38233 * @extends Roo.form.TextField
38234 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38236 * Creates a new NumberField
38237 * @param {Object} config Configuration options
38239 Roo.form.NumberField = function(config){
38240 Roo.form.NumberField.superclass.constructor.call(this, config);
38243 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38245 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38247 fieldClass: "x-form-field x-form-num-field",
38249 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38251 allowDecimals : true,
38253 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38255 decimalSeparator : ".",
38257 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38259 decimalPrecision : 2,
38261 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38263 allowNegative : true,
38265 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38267 minValue : Number.NEGATIVE_INFINITY,
38269 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38271 maxValue : Number.MAX_VALUE,
38273 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38275 minText : "The minimum value for this field is {0}",
38277 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38279 maxText : "The maximum value for this field is {0}",
38281 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38282 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38284 nanText : "{0} is not a valid number",
38287 initEvents : function(){
38288 Roo.form.NumberField.superclass.initEvents.call(this);
38289 var allowed = "0123456789";
38290 if(this.allowDecimals){
38291 allowed += this.decimalSeparator;
38293 if(this.allowNegative){
38296 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38297 var keyPress = function(e){
38298 var k = e.getKey();
38299 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38302 var c = e.getCharCode();
38303 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38307 this.el.on("keypress", keyPress, this);
38311 validateValue : function(value){
38312 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38315 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38318 var num = this.parseValue(value);
38320 this.markInvalid(String.format(this.nanText, value));
38323 if(num < this.minValue){
38324 this.markInvalid(String.format(this.minText, this.minValue));
38327 if(num > this.maxValue){
38328 this.markInvalid(String.format(this.maxText, this.maxValue));
38334 getValue : function(){
38335 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38339 parseValue : function(value){
38340 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38341 return isNaN(value) ? '' : value;
38345 fixPrecision : function(value){
38346 var nan = isNaN(value);
38347 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38348 return nan ? '' : value;
38350 return parseFloat(value).toFixed(this.decimalPrecision);
38353 setValue : function(v){
38354 v = this.fixPrecision(v);
38355 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38359 decimalPrecisionFcn : function(v){
38360 return Math.floor(v);
38363 beforeBlur : function(){
38364 var v = this.parseValue(this.getRawValue());
38371 * Ext JS Library 1.1.1
38372 * Copyright(c) 2006-2007, Ext JS, LLC.
38374 * Originally Released Under LGPL - original licence link has changed is not relivant.
38377 * <script type="text/javascript">
38381 * @class Roo.form.DateField
38382 * @extends Roo.form.TriggerField
38383 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38385 * Create a new DateField
38386 * @param {Object} config
38388 Roo.form.DateField = function(config){
38389 Roo.form.DateField.superclass.constructor.call(this, config);
38395 * Fires when a date is selected
38396 * @param {Roo.form.DateField} combo This combo box
38397 * @param {Date} date The date selected
38404 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38405 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38406 this.ddMatch = null;
38407 if(this.disabledDates){
38408 var dd = this.disabledDates;
38410 for(var i = 0; i < dd.length; i++){
38412 if(i != dd.length-1) re += "|";
38414 this.ddMatch = new RegExp(re + ")");
38418 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38420 * @cfg {String} format
38421 * The default date format string which can be overriden for localization support. The format must be
38422 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38426 * @cfg {String} altFormats
38427 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38428 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38430 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38432 * @cfg {Array} disabledDays
38433 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38435 disabledDays : null,
38437 * @cfg {String} disabledDaysText
38438 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38440 disabledDaysText : "Disabled",
38442 * @cfg {Array} disabledDates
38443 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38444 * expression so they are very powerful. Some examples:
38446 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38447 * <li>["03/08", "09/16"] would disable those days for every year</li>
38448 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38449 * <li>["03/../2006"] would disable every day in March 2006</li>
38450 * <li>["^03"] would disable every day in every March</li>
38452 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38453 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38455 disabledDates : null,
38457 * @cfg {String} disabledDatesText
38458 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38460 disabledDatesText : "Disabled",
38462 * @cfg {Date/String} minValue
38463 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38464 * valid format (defaults to null).
38468 * @cfg {Date/String} maxValue
38469 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38470 * valid format (defaults to null).
38474 * @cfg {String} minText
38475 * The error text to display when the date in the cell is before minValue (defaults to
38476 * 'The date in this field must be after {minValue}').
38478 minText : "The date in this field must be equal to or after {0}",
38480 * @cfg {String} maxText
38481 * The error text to display when the date in the cell is after maxValue (defaults to
38482 * 'The date in this field must be before {maxValue}').
38484 maxText : "The date in this field must be equal to or before {0}",
38486 * @cfg {String} invalidText
38487 * The error text to display when the date in the field is invalid (defaults to
38488 * '{value} is not a valid date - it must be in the format {format}').
38490 invalidText : "{0} is not a valid date - it must be in the format {1}",
38492 * @cfg {String} triggerClass
38493 * An additional CSS class used to style the trigger button. The trigger will always get the
38494 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38495 * which displays a calendar icon).
38497 triggerClass : 'x-form-date-trigger',
38501 * @cfg {Boolean} useIso
38502 * if enabled, then the date field will use a hidden field to store the
38503 * real value as iso formated date. default (false)
38507 * @cfg {String/Object} autoCreate
38508 * A DomHelper element spec, or true for a default element spec (defaults to
38509 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38512 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38515 hiddenField: false,
38517 onRender : function(ct, position)
38519 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38521 //this.el.dom.removeAttribute('name');
38522 Roo.log("Changing name?");
38523 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38524 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38526 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38527 // prevent input submission
38528 this.hiddenName = this.name;
38535 validateValue : function(value)
38537 value = this.formatDate(value);
38538 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38539 Roo.log('super failed');
38542 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38545 var svalue = value;
38546 value = this.parseDate(value);
38548 Roo.log('parse date failed' + svalue);
38549 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38552 var time = value.getTime();
38553 if(this.minValue && time < this.minValue.getTime()){
38554 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38557 if(this.maxValue && time > this.maxValue.getTime()){
38558 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38561 if(this.disabledDays){
38562 var day = value.getDay();
38563 for(var i = 0; i < this.disabledDays.length; i++) {
38564 if(day === this.disabledDays[i]){
38565 this.markInvalid(this.disabledDaysText);
38570 var fvalue = this.formatDate(value);
38571 if(this.ddMatch && this.ddMatch.test(fvalue)){
38572 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38579 // Provides logic to override the default TriggerField.validateBlur which just returns true
38580 validateBlur : function(){
38581 return !this.menu || !this.menu.isVisible();
38584 getName: function()
38586 // returns hidden if it's set..
38587 if (!this.rendered) {return ''};
38588 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38593 * Returns the current date value of the date field.
38594 * @return {Date} The date value
38596 getValue : function(){
38598 return this.hiddenField ?
38599 this.hiddenField.value :
38600 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38604 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38605 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38606 * (the default format used is "m/d/y").
38609 //All of these calls set the same date value (May 4, 2006)
38611 //Pass a date object:
38612 var dt = new Date('5/4/06');
38613 dateField.setValue(dt);
38615 //Pass a date string (default format):
38616 dateField.setValue('5/4/06');
38618 //Pass a date string (custom format):
38619 dateField.format = 'Y-m-d';
38620 dateField.setValue('2006-5-4');
38622 * @param {String/Date} date The date or valid date string
38624 setValue : function(date){
38625 if (this.hiddenField) {
38626 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38628 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38629 // make sure the value field is always stored as a date..
38630 this.value = this.parseDate(date);
38636 parseDate : function(value){
38637 if(!value || value instanceof Date){
38640 var v = Date.parseDate(value, this.format);
38641 if (!v && this.useIso) {
38642 v = Date.parseDate(value, 'Y-m-d');
38644 if(!v && this.altFormats){
38645 if(!this.altFormatsArray){
38646 this.altFormatsArray = this.altFormats.split("|");
38648 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38649 v = Date.parseDate(value, this.altFormatsArray[i]);
38656 formatDate : function(date, fmt){
38657 return (!date || !(date instanceof Date)) ?
38658 date : date.dateFormat(fmt || this.format);
38663 select: function(m, d){
38666 this.fireEvent('select', this, d);
38668 show : function(){ // retain focus styling
38672 this.focus.defer(10, this);
38673 var ml = this.menuListeners;
38674 this.menu.un("select", ml.select, this);
38675 this.menu.un("show", ml.show, this);
38676 this.menu.un("hide", ml.hide, this);
38681 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38682 onTriggerClick : function(){
38686 if(this.menu == null){
38687 this.menu = new Roo.menu.DateMenu();
38689 Roo.apply(this.menu.picker, {
38690 showClear: this.allowBlank,
38691 minDate : this.minValue,
38692 maxDate : this.maxValue,
38693 disabledDatesRE : this.ddMatch,
38694 disabledDatesText : this.disabledDatesText,
38695 disabledDays : this.disabledDays,
38696 disabledDaysText : this.disabledDaysText,
38697 format : this.useIso ? 'Y-m-d' : this.format,
38698 minText : String.format(this.minText, this.formatDate(this.minValue)),
38699 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38701 this.menu.on(Roo.apply({}, this.menuListeners, {
38704 this.menu.picker.setValue(this.getValue() || new Date());
38705 this.menu.show(this.el, "tl-bl?");
38708 beforeBlur : function(){
38709 var v = this.parseDate(this.getRawValue());
38719 isDirty : function() {
38720 if(this.disabled) {
38724 if(typeof(this.startValue) === 'undefined'){
38728 return String(this.getValue()) !== String(this.startValue);
38733 * Ext JS Library 1.1.1
38734 * Copyright(c) 2006-2007, Ext JS, LLC.
38736 * Originally Released Under LGPL - original licence link has changed is not relivant.
38739 * <script type="text/javascript">
38743 * @class Roo.form.MonthField
38744 * @extends Roo.form.TriggerField
38745 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38747 * Create a new MonthField
38748 * @param {Object} config
38750 Roo.form.MonthField = function(config){
38752 Roo.form.MonthField.superclass.constructor.call(this, config);
38758 * Fires when a date is selected
38759 * @param {Roo.form.MonthFieeld} combo This combo box
38760 * @param {Date} date The date selected
38767 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38768 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38769 this.ddMatch = null;
38770 if(this.disabledDates){
38771 var dd = this.disabledDates;
38773 for(var i = 0; i < dd.length; i++){
38775 if(i != dd.length-1) re += "|";
38777 this.ddMatch = new RegExp(re + ")");
38781 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38783 * @cfg {String} format
38784 * The default date format string which can be overriden for localization support. The format must be
38785 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38789 * @cfg {String} altFormats
38790 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38791 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38793 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38795 * @cfg {Array} disabledDays
38796 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38798 disabledDays : [0,1,2,3,4,5,6],
38800 * @cfg {String} disabledDaysText
38801 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38803 disabledDaysText : "Disabled",
38805 * @cfg {Array} disabledDates
38806 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38807 * expression so they are very powerful. Some examples:
38809 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38810 * <li>["03/08", "09/16"] would disable those days for every year</li>
38811 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38812 * <li>["03/../2006"] would disable every day in March 2006</li>
38813 * <li>["^03"] would disable every day in every March</li>
38815 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38816 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38818 disabledDates : null,
38820 * @cfg {String} disabledDatesText
38821 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38823 disabledDatesText : "Disabled",
38825 * @cfg {Date/String} minValue
38826 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38827 * valid format (defaults to null).
38831 * @cfg {Date/String} maxValue
38832 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38833 * valid format (defaults to null).
38837 * @cfg {String} minText
38838 * The error text to display when the date in the cell is before minValue (defaults to
38839 * 'The date in this field must be after {minValue}').
38841 minText : "The date in this field must be equal to or after {0}",
38843 * @cfg {String} maxTextf
38844 * The error text to display when the date in the cell is after maxValue (defaults to
38845 * 'The date in this field must be before {maxValue}').
38847 maxText : "The date in this field must be equal to or before {0}",
38849 * @cfg {String} invalidText
38850 * The error text to display when the date in the field is invalid (defaults to
38851 * '{value} is not a valid date - it must be in the format {format}').
38853 invalidText : "{0} is not a valid date - it must be in the format {1}",
38855 * @cfg {String} triggerClass
38856 * An additional CSS class used to style the trigger button. The trigger will always get the
38857 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38858 * which displays a calendar icon).
38860 triggerClass : 'x-form-date-trigger',
38864 * @cfg {Boolean} useIso
38865 * if enabled, then the date field will use a hidden field to store the
38866 * real value as iso formated date. default (true)
38870 * @cfg {String/Object} autoCreate
38871 * A DomHelper element spec, or true for a default element spec (defaults to
38872 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38875 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38878 hiddenField: false,
38880 hideMonthPicker : false,
38882 onRender : function(ct, position)
38884 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38886 this.el.dom.removeAttribute('name');
38887 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38889 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38890 // prevent input submission
38891 this.hiddenName = this.name;
38898 validateValue : function(value)
38900 value = this.formatDate(value);
38901 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38904 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38907 var svalue = value;
38908 value = this.parseDate(value);
38910 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38913 var time = value.getTime();
38914 if(this.minValue && time < this.minValue.getTime()){
38915 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38918 if(this.maxValue && time > this.maxValue.getTime()){
38919 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38922 /*if(this.disabledDays){
38923 var day = value.getDay();
38924 for(var i = 0; i < this.disabledDays.length; i++) {
38925 if(day === this.disabledDays[i]){
38926 this.markInvalid(this.disabledDaysText);
38932 var fvalue = this.formatDate(value);
38933 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38934 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38942 // Provides logic to override the default TriggerField.validateBlur which just returns true
38943 validateBlur : function(){
38944 return !this.menu || !this.menu.isVisible();
38948 * Returns the current date value of the date field.
38949 * @return {Date} The date value
38951 getValue : function(){
38955 return this.hiddenField ?
38956 this.hiddenField.value :
38957 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38961 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38962 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38963 * (the default format used is "m/d/y").
38966 //All of these calls set the same date value (May 4, 2006)
38968 //Pass a date object:
38969 var dt = new Date('5/4/06');
38970 monthField.setValue(dt);
38972 //Pass a date string (default format):
38973 monthField.setValue('5/4/06');
38975 //Pass a date string (custom format):
38976 monthField.format = 'Y-m-d';
38977 monthField.setValue('2006-5-4');
38979 * @param {String/Date} date The date or valid date string
38981 setValue : function(date){
38982 Roo.log('month setValue' + date);
38983 // can only be first of month..
38985 var val = this.parseDate(date);
38987 if (this.hiddenField) {
38988 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38990 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38991 this.value = this.parseDate(date);
38995 parseDate : function(value){
38996 if(!value || value instanceof Date){
38997 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39000 var v = Date.parseDate(value, this.format);
39001 if (!v && this.useIso) {
39002 v = Date.parseDate(value, 'Y-m-d');
39006 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39010 if(!v && this.altFormats){
39011 if(!this.altFormatsArray){
39012 this.altFormatsArray = this.altFormats.split("|");
39014 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39015 v = Date.parseDate(value, this.altFormatsArray[i]);
39022 formatDate : function(date, fmt){
39023 return (!date || !(date instanceof Date)) ?
39024 date : date.dateFormat(fmt || this.format);
39029 select: function(m, d){
39031 this.fireEvent('select', this, d);
39033 show : function(){ // retain focus styling
39037 this.focus.defer(10, this);
39038 var ml = this.menuListeners;
39039 this.menu.un("select", ml.select, this);
39040 this.menu.un("show", ml.show, this);
39041 this.menu.un("hide", ml.hide, this);
39045 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39046 onTriggerClick : function(){
39050 if(this.menu == null){
39051 this.menu = new Roo.menu.DateMenu();
39055 Roo.apply(this.menu.picker, {
39057 showClear: this.allowBlank,
39058 minDate : this.minValue,
39059 maxDate : this.maxValue,
39060 disabledDatesRE : this.ddMatch,
39061 disabledDatesText : this.disabledDatesText,
39063 format : this.useIso ? 'Y-m-d' : this.format,
39064 minText : String.format(this.minText, this.formatDate(this.minValue)),
39065 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39068 this.menu.on(Roo.apply({}, this.menuListeners, {
39076 // hide month picker get's called when we called by 'before hide';
39078 var ignorehide = true;
39079 p.hideMonthPicker = function(disableAnim){
39083 if(this.monthPicker){
39084 Roo.log("hideMonthPicker called");
39085 if(disableAnim === true){
39086 this.monthPicker.hide();
39088 this.monthPicker.slideOut('t', {duration:.2});
39089 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39090 p.fireEvent("select", this, this.value);
39096 Roo.log('picker set value');
39097 Roo.log(this.getValue());
39098 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39099 m.show(this.el, 'tl-bl?');
39100 ignorehide = false;
39101 // this will trigger hideMonthPicker..
39104 // hidden the day picker
39105 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39111 p.showMonthPicker.defer(100, p);
39117 beforeBlur : function(){
39118 var v = this.parseDate(this.getRawValue());
39124 /** @cfg {Boolean} grow @hide */
39125 /** @cfg {Number} growMin @hide */
39126 /** @cfg {Number} growMax @hide */
39133 * Ext JS Library 1.1.1
39134 * Copyright(c) 2006-2007, Ext JS, LLC.
39136 * Originally Released Under LGPL - original licence link has changed is not relivant.
39139 * <script type="text/javascript">
39144 * @class Roo.form.ComboBox
39145 * @extends Roo.form.TriggerField
39146 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39148 * Create a new ComboBox.
39149 * @param {Object} config Configuration options
39151 Roo.form.ComboBox = function(config){
39152 Roo.form.ComboBox.superclass.constructor.call(this, config);
39156 * Fires when the dropdown list is expanded
39157 * @param {Roo.form.ComboBox} combo This combo box
39162 * Fires when the dropdown list is collapsed
39163 * @param {Roo.form.ComboBox} combo This combo box
39167 * @event beforeselect
39168 * Fires before a list item is selected. Return false to cancel the selection.
39169 * @param {Roo.form.ComboBox} combo This combo box
39170 * @param {Roo.data.Record} record The data record returned from the underlying store
39171 * @param {Number} index The index of the selected item in the dropdown list
39173 'beforeselect' : true,
39176 * Fires when a list item is selected
39177 * @param {Roo.form.ComboBox} combo This combo box
39178 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39179 * @param {Number} index The index of the selected item in the dropdown list
39183 * @event beforequery
39184 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39185 * The event object passed has these properties:
39186 * @param {Roo.form.ComboBox} combo This combo box
39187 * @param {String} query The query
39188 * @param {Boolean} forceAll true to force "all" query
39189 * @param {Boolean} cancel true to cancel the query
39190 * @param {Object} e The query event object
39192 'beforequery': true,
39195 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39196 * @param {Roo.form.ComboBox} combo This combo box
39201 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39202 * @param {Roo.form.ComboBox} combo This combo box
39203 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39209 if(this.transform){
39210 this.allowDomMove = false;
39211 var s = Roo.getDom(this.transform);
39212 if(!this.hiddenName){
39213 this.hiddenName = s.name;
39216 this.mode = 'local';
39217 var d = [], opts = s.options;
39218 for(var i = 0, len = opts.length;i < len; i++){
39220 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39222 this.value = value;
39224 d.push([value, o.text]);
39226 this.store = new Roo.data.SimpleStore({
39228 fields: ['value', 'text'],
39231 this.valueField = 'value';
39232 this.displayField = 'text';
39234 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39235 if(!this.lazyRender){
39236 this.target = true;
39237 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39238 s.parentNode.removeChild(s); // remove it
39239 this.render(this.el.parentNode);
39241 s.parentNode.removeChild(s); // remove it
39246 this.store = Roo.factory(this.store, Roo.data);
39249 this.selectedIndex = -1;
39250 if(this.mode == 'local'){
39251 if(config.queryDelay === undefined){
39252 this.queryDelay = 10;
39254 if(config.minChars === undefined){
39260 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39262 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39265 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39266 * rendering into an Roo.Editor, defaults to false)
39269 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39270 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39273 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39276 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39277 * the dropdown list (defaults to undefined, with no header element)
39281 * @cfg {String/Roo.Template} tpl The template to use to render the output
39285 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39287 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39289 listWidth: undefined,
39291 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39292 * mode = 'remote' or 'text' if mode = 'local')
39294 displayField: undefined,
39296 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39297 * mode = 'remote' or 'value' if mode = 'local').
39298 * Note: use of a valueField requires the user make a selection
39299 * in order for a value to be mapped.
39301 valueField: undefined,
39305 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39306 * field's data value (defaults to the underlying DOM element's name)
39308 hiddenName: undefined,
39310 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39314 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39316 selectedClass: 'x-combo-selected',
39318 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39319 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39320 * which displays a downward arrow icon).
39322 triggerClass : 'x-form-arrow-trigger',
39324 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39328 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39329 * anchor positions (defaults to 'tl-bl')
39331 listAlign: 'tl-bl?',
39333 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39337 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39338 * query specified by the allQuery config option (defaults to 'query')
39340 triggerAction: 'query',
39342 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39343 * (defaults to 4, does not apply if editable = false)
39347 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39348 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39352 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39353 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39357 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39358 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39362 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39363 * when editable = true (defaults to false)
39365 selectOnFocus:false,
39367 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39369 queryParam: 'query',
39371 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39372 * when mode = 'remote' (defaults to 'Loading...')
39374 loadingText: 'Loading...',
39376 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39380 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39384 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39385 * traditional select (defaults to true)
39389 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39393 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39397 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39398 * listWidth has a higher value)
39402 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39403 * allow the user to set arbitrary text into the field (defaults to false)
39405 forceSelection:false,
39407 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39408 * if typeAhead = true (defaults to 250)
39410 typeAheadDelay : 250,
39412 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39413 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39415 valueNotFoundText : undefined,
39417 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39419 blockFocus : false,
39422 * @cfg {Boolean} disableClear Disable showing of clear button.
39424 disableClear : false,
39426 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39428 alwaysQuery : false,
39434 // element that contains real text value.. (when hidden is used..)
39437 onRender : function(ct, position){
39438 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39439 if(this.hiddenName){
39440 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39442 this.hiddenField.value =
39443 this.hiddenValue !== undefined ? this.hiddenValue :
39444 this.value !== undefined ? this.value : '';
39446 // prevent input submission
39447 this.el.dom.removeAttribute('name');
39452 this.el.dom.setAttribute('autocomplete', 'off');
39455 var cls = 'x-combo-list';
39457 this.list = new Roo.Layer({
39458 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39461 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39462 this.list.setWidth(lw);
39463 this.list.swallowEvent('mousewheel');
39464 this.assetHeight = 0;
39467 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39468 this.assetHeight += this.header.getHeight();
39471 this.innerList = this.list.createChild({cls:cls+'-inner'});
39472 this.innerList.on('mouseover', this.onViewOver, this);
39473 this.innerList.on('mousemove', this.onViewMove, this);
39474 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39476 if(this.allowBlank && !this.pageSize && !this.disableClear){
39477 this.footer = this.list.createChild({cls:cls+'-ft'});
39478 this.pageTb = new Roo.Toolbar(this.footer);
39482 this.footer = this.list.createChild({cls:cls+'-ft'});
39483 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39484 {pageSize: this.pageSize});
39488 if (this.pageTb && this.allowBlank && !this.disableClear) {
39490 this.pageTb.add(new Roo.Toolbar.Fill(), {
39491 cls: 'x-btn-icon x-btn-clear',
39493 handler: function()
39496 _this.clearValue();
39497 _this.onSelect(false, -1);
39502 this.assetHeight += this.footer.getHeight();
39507 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39510 this.view = new Roo.View(this.innerList, this.tpl, {
39511 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39514 this.view.on('click', this.onViewClick, this);
39516 this.store.on('beforeload', this.onBeforeLoad, this);
39517 this.store.on('load', this.onLoad, this);
39518 this.store.on('loadexception', this.onLoadException, this);
39520 if(this.resizable){
39521 this.resizer = new Roo.Resizable(this.list, {
39522 pinned:true, handles:'se'
39524 this.resizer.on('resize', function(r, w, h){
39525 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39526 this.listWidth = w;
39527 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39528 this.restrictHeight();
39530 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39532 if(!this.editable){
39533 this.editable = true;
39534 this.setEditable(false);
39538 if (typeof(this.events.add.listeners) != 'undefined') {
39540 this.addicon = this.wrap.createChild(
39541 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39543 this.addicon.on('click', function(e) {
39544 this.fireEvent('add', this);
39547 if (typeof(this.events.edit.listeners) != 'undefined') {
39549 this.editicon = this.wrap.createChild(
39550 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39551 if (this.addicon) {
39552 this.editicon.setStyle('margin-left', '40px');
39554 this.editicon.on('click', function(e) {
39556 // we fire even if inothing is selected..
39557 this.fireEvent('edit', this, this.lastData );
39567 initEvents : function(){
39568 Roo.form.ComboBox.superclass.initEvents.call(this);
39570 this.keyNav = new Roo.KeyNav(this.el, {
39571 "up" : function(e){
39572 this.inKeyMode = true;
39576 "down" : function(e){
39577 if(!this.isExpanded()){
39578 this.onTriggerClick();
39580 this.inKeyMode = true;
39585 "enter" : function(e){
39586 this.onViewClick();
39590 "esc" : function(e){
39594 "tab" : function(e){
39595 this.onViewClick(false);
39596 this.fireEvent("specialkey", this, e);
39602 doRelay : function(foo, bar, hname){
39603 if(hname == 'down' || this.scope.isExpanded()){
39604 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39611 this.queryDelay = Math.max(this.queryDelay || 10,
39612 this.mode == 'local' ? 10 : 250);
39613 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39614 if(this.typeAhead){
39615 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39617 if(this.editable !== false){
39618 this.el.on("keyup", this.onKeyUp, this);
39620 if(this.forceSelection){
39621 this.on('blur', this.doForce, this);
39625 onDestroy : function(){
39627 this.view.setStore(null);
39628 this.view.el.removeAllListeners();
39629 this.view.el.remove();
39630 this.view.purgeListeners();
39633 this.list.destroy();
39636 this.store.un('beforeload', this.onBeforeLoad, this);
39637 this.store.un('load', this.onLoad, this);
39638 this.store.un('loadexception', this.onLoadException, this);
39640 Roo.form.ComboBox.superclass.onDestroy.call(this);
39644 fireKey : function(e){
39645 if(e.isNavKeyPress() && !this.list.isVisible()){
39646 this.fireEvent("specialkey", this, e);
39651 onResize: function(w, h){
39652 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39654 if(typeof w != 'number'){
39655 // we do not handle it!?!?
39658 var tw = this.trigger.getWidth();
39659 tw += this.addicon ? this.addicon.getWidth() : 0;
39660 tw += this.editicon ? this.editicon.getWidth() : 0;
39662 this.el.setWidth( this.adjustWidth('input', x));
39664 this.trigger.setStyle('left', x+'px');
39666 if(this.list && this.listWidth === undefined){
39667 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39668 this.list.setWidth(lw);
39669 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39677 * Allow or prevent the user from directly editing the field text. If false is passed,
39678 * the user will only be able to select from the items defined in the dropdown list. This method
39679 * is the runtime equivalent of setting the 'editable' config option at config time.
39680 * @param {Boolean} value True to allow the user to directly edit the field text
39682 setEditable : function(value){
39683 if(value == this.editable){
39686 this.editable = value;
39688 this.el.dom.setAttribute('readOnly', true);
39689 this.el.on('mousedown', this.onTriggerClick, this);
39690 this.el.addClass('x-combo-noedit');
39692 this.el.dom.setAttribute('readOnly', false);
39693 this.el.un('mousedown', this.onTriggerClick, this);
39694 this.el.removeClass('x-combo-noedit');
39699 onBeforeLoad : function(){
39700 if(!this.hasFocus){
39703 this.innerList.update(this.loadingText ?
39704 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39705 this.restrictHeight();
39706 this.selectedIndex = -1;
39710 onLoad : function(){
39711 if(!this.hasFocus){
39714 if(this.store.getCount() > 0){
39716 this.restrictHeight();
39717 if(this.lastQuery == this.allQuery){
39719 this.el.dom.select();
39721 if(!this.selectByValue(this.value, true)){
39722 this.select(0, true);
39726 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39727 this.taTask.delay(this.typeAheadDelay);
39731 this.onEmptyResults();
39736 onLoadException : function()
39739 Roo.log(this.store.reader.jsonData);
39740 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39741 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39747 onTypeAhead : function(){
39748 if(this.store.getCount() > 0){
39749 var r = this.store.getAt(0);
39750 var newValue = r.data[this.displayField];
39751 var len = newValue.length;
39752 var selStart = this.getRawValue().length;
39753 if(selStart != len){
39754 this.setRawValue(newValue);
39755 this.selectText(selStart, newValue.length);
39761 onSelect : function(record, index){
39762 if(this.fireEvent('beforeselect', this, record, index) !== false){
39763 this.setFromData(index > -1 ? record.data : false);
39765 this.fireEvent('select', this, record, index);
39770 * Returns the currently selected field value or empty string if no value is set.
39771 * @return {String} value The selected value
39773 getValue : function(){
39774 if(this.valueField){
39775 return typeof this.value != 'undefined' ? this.value : '';
39777 return Roo.form.ComboBox.superclass.getValue.call(this);
39782 * Clears any text/value currently set in the field
39784 clearValue : function(){
39785 if(this.hiddenField){
39786 this.hiddenField.value = '';
39789 this.setRawValue('');
39790 this.lastSelectionText = '';
39795 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39796 * will be displayed in the field. If the value does not match the data value of an existing item,
39797 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39798 * Otherwise the field will be blank (although the value will still be set).
39799 * @param {String} value The value to match
39801 setValue : function(v){
39803 if(this.valueField){
39804 var r = this.findRecord(this.valueField, v);
39806 text = r.data[this.displayField];
39807 }else if(this.valueNotFoundText !== undefined){
39808 text = this.valueNotFoundText;
39811 this.lastSelectionText = text;
39812 if(this.hiddenField){
39813 this.hiddenField.value = v;
39815 Roo.form.ComboBox.superclass.setValue.call(this, text);
39819 * @property {Object} the last set data for the element
39824 * Sets the value of the field based on a object which is related to the record format for the store.
39825 * @param {Object} value the value to set as. or false on reset?
39827 setFromData : function(o){
39828 var dv = ''; // display value
39829 var vv = ''; // value value..
39831 if (this.displayField) {
39832 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39834 // this is an error condition!!!
39835 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39838 if(this.valueField){
39839 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39841 if(this.hiddenField){
39842 this.hiddenField.value = vv;
39844 this.lastSelectionText = dv;
39845 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39849 // no hidden field.. - we store the value in 'value', but still display
39850 // display field!!!!
39851 this.lastSelectionText = dv;
39852 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39858 reset : function(){
39859 // overridden so that last data is reset..
39860 this.setValue(this.resetValue);
39861 this.clearInvalid();
39862 this.lastData = false;
39864 this.view.clearSelections();
39868 findRecord : function(prop, value){
39870 if(this.store.getCount() > 0){
39871 this.store.each(function(r){
39872 if(r.data[prop] == value){
39882 getName: function()
39884 // returns hidden if it's set..
39885 if (!this.rendered) {return ''};
39886 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39890 onViewMove : function(e, t){
39891 this.inKeyMode = false;
39895 onViewOver : function(e, t){
39896 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39899 var item = this.view.findItemFromChild(t);
39901 var index = this.view.indexOf(item);
39902 this.select(index, false);
39907 onViewClick : function(doFocus)
39909 var index = this.view.getSelectedIndexes()[0];
39910 var r = this.store.getAt(index);
39912 this.onSelect(r, index);
39914 if(doFocus !== false && !this.blockFocus){
39920 restrictHeight : function(){
39921 this.innerList.dom.style.height = '';
39922 var inner = this.innerList.dom;
39923 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39924 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39925 this.list.beginUpdate();
39926 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39927 this.list.alignTo(this.el, this.listAlign);
39928 this.list.endUpdate();
39932 onEmptyResults : function(){
39937 * Returns true if the dropdown list is expanded, else false.
39939 isExpanded : function(){
39940 return this.list.isVisible();
39944 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39945 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39946 * @param {String} value The data value of the item to select
39947 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39948 * selected item if it is not currently in view (defaults to true)
39949 * @return {Boolean} True if the value matched an item in the list, else false
39951 selectByValue : function(v, scrollIntoView){
39952 if(v !== undefined && v !== null){
39953 var r = this.findRecord(this.valueField || this.displayField, v);
39955 this.select(this.store.indexOf(r), scrollIntoView);
39963 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39964 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39965 * @param {Number} index The zero-based index of the list item to select
39966 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39967 * selected item if it is not currently in view (defaults to true)
39969 select : function(index, scrollIntoView){
39970 this.selectedIndex = index;
39971 this.view.select(index);
39972 if(scrollIntoView !== false){
39973 var el = this.view.getNode(index);
39975 this.innerList.scrollChildIntoView(el, false);
39981 selectNext : function(){
39982 var ct = this.store.getCount();
39984 if(this.selectedIndex == -1){
39986 }else if(this.selectedIndex < ct-1){
39987 this.select(this.selectedIndex+1);
39993 selectPrev : function(){
39994 var ct = this.store.getCount();
39996 if(this.selectedIndex == -1){
39998 }else if(this.selectedIndex != 0){
39999 this.select(this.selectedIndex-1);
40005 onKeyUp : function(e){
40006 if(this.editable !== false && !e.isSpecialKey()){
40007 this.lastKey = e.getKey();
40008 this.dqTask.delay(this.queryDelay);
40013 validateBlur : function(){
40014 return !this.list || !this.list.isVisible();
40018 initQuery : function(){
40019 this.doQuery(this.getRawValue());
40023 doForce : function(){
40024 if(this.el.dom.value.length > 0){
40025 this.el.dom.value =
40026 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40032 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40033 * query allowing the query action to be canceled if needed.
40034 * @param {String} query The SQL query to execute
40035 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40036 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40037 * saved in the current store (defaults to false)
40039 doQuery : function(q, forceAll){
40040 if(q === undefined || q === null){
40045 forceAll: forceAll,
40049 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40053 forceAll = qe.forceAll;
40054 if(forceAll === true || (q.length >= this.minChars)){
40055 if(this.lastQuery != q || this.alwaysQuery){
40056 this.lastQuery = q;
40057 if(this.mode == 'local'){
40058 this.selectedIndex = -1;
40060 this.store.clearFilter();
40062 this.store.filter(this.displayField, q);
40066 this.store.baseParams[this.queryParam] = q;
40068 params: this.getParams(q)
40073 this.selectedIndex = -1;
40080 getParams : function(q){
40082 //p[this.queryParam] = q;
40085 p.limit = this.pageSize;
40091 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40093 collapse : function(){
40094 if(!this.isExpanded()){
40098 Roo.get(document).un('mousedown', this.collapseIf, this);
40099 Roo.get(document).un('mousewheel', this.collapseIf, this);
40100 if (!this.editable) {
40101 Roo.get(document).un('keydown', this.listKeyPress, this);
40103 this.fireEvent('collapse', this);
40107 collapseIf : function(e){
40108 if(!e.within(this.wrap) && !e.within(this.list)){
40114 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40116 expand : function(){
40117 if(this.isExpanded() || !this.hasFocus){
40120 this.list.alignTo(this.el, this.listAlign);
40122 Roo.get(document).on('mousedown', this.collapseIf, this);
40123 Roo.get(document).on('mousewheel', this.collapseIf, this);
40124 if (!this.editable) {
40125 Roo.get(document).on('keydown', this.listKeyPress, this);
40128 this.fireEvent('expand', this);
40132 // Implements the default empty TriggerField.onTriggerClick function
40133 onTriggerClick : function(){
40137 if(this.isExpanded()){
40139 if (!this.blockFocus) {
40144 this.hasFocus = true;
40145 if(this.triggerAction == 'all') {
40146 this.doQuery(this.allQuery, true);
40148 this.doQuery(this.getRawValue());
40150 if (!this.blockFocus) {
40155 listKeyPress : function(e)
40157 //Roo.log('listkeypress');
40158 // scroll to first matching element based on key pres..
40159 if (e.isSpecialKey()) {
40162 var k = String.fromCharCode(e.getKey()).toUpperCase();
40165 var csel = this.view.getSelectedNodes();
40166 var cselitem = false;
40168 var ix = this.view.indexOf(csel[0]);
40169 cselitem = this.store.getAt(ix);
40170 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40176 this.store.each(function(v) {
40178 // start at existing selection.
40179 if (cselitem.id == v.id) {
40185 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40186 match = this.store.indexOf(v);
40191 if (match === false) {
40192 return true; // no more action?
40195 this.view.select(match);
40196 var sn = Roo.get(this.view.getSelectedNodes()[0])
40197 sn.scrollIntoView(sn.dom.parentNode, false);
40201 * @cfg {Boolean} grow
40205 * @cfg {Number} growMin
40209 * @cfg {Number} growMax
40217 * Copyright(c) 2010-2012, Roo J Solutions Limited
40224 * @class Roo.form.ComboBoxArray
40225 * @extends Roo.form.TextField
40226 * A facebook style adder... for lists of email / people / countries etc...
40227 * pick multiple items from a combo box, and shows each one.
40229 * Fred [x] Brian [x] [Pick another |v]
40232 * For this to work: it needs various extra information
40233 * - normal combo problay has
40235 * + displayField, valueField
40237 * For our purpose...
40240 * If we change from 'extends' to wrapping...
40247 * Create a new ComboBoxArray.
40248 * @param {Object} config Configuration options
40252 Roo.form.ComboBoxArray = function(config)
40257 * Fires when remove the value from the list
40258 * @param {Roo.form.ComboBoxArray} _self This combo box array
40259 * @param {Roo.form.ComboBoxArray.Item} item removed item
40266 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40268 this.items = new Roo.util.MixedCollection(false);
40270 // construct the child combo...
40280 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40283 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40288 // behavies liek a hiddne field
40289 inputType: 'hidden',
40291 * @cfg {Number} width The width of the box that displays the selected element
40298 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40302 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40304 hiddenName : false,
40307 // private the array of items that are displayed..
40309 // private - the hidden field el.
40311 // private - the filed el..
40314 //validateValue : function() { return true; }, // all values are ok!
40315 //onAddClick: function() { },
40317 onRender : function(ct, position)
40320 // create the standard hidden element
40321 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40324 // give fake names to child combo;
40325 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40326 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40328 this.combo = Roo.factory(this.combo, Roo.form);
40329 this.combo.onRender(ct, position);
40330 if (typeof(this.combo.width) != 'undefined') {
40331 this.combo.onResize(this.combo.width,0);
40334 this.combo.initEvents();
40336 // assigned so form know we need to do this..
40337 this.store = this.combo.store;
40338 this.valueField = this.combo.valueField;
40339 this.displayField = this.combo.displayField ;
40342 this.combo.wrap.addClass('x-cbarray-grp');
40344 var cbwrap = this.combo.wrap.createChild(
40345 {tag: 'div', cls: 'x-cbarray-cb'},
40350 this.hiddenEl = this.combo.wrap.createChild({
40351 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40353 this.el = this.combo.wrap.createChild({
40354 tag: 'input', type:'hidden' , name: this.name, value : ''
40356 // this.el.dom.removeAttribute("name");
40359 this.outerWrap = this.combo.wrap;
40360 this.wrap = cbwrap;
40362 this.outerWrap.setWidth(this.width);
40363 this.outerWrap.dom.removeChild(this.el.dom);
40365 this.wrap.dom.appendChild(this.el.dom);
40366 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40367 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40369 this.combo.trigger.setStyle('position','relative');
40370 this.combo.trigger.setStyle('left', '0px');
40371 this.combo.trigger.setStyle('top', '2px');
40373 this.combo.el.setStyle('vertical-align', 'text-bottom');
40375 //this.trigger.setStyle('vertical-align', 'top');
40377 // this should use the code from combo really... on('add' ....)
40381 this.adder = this.outerWrap.createChild(
40382 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40384 this.adder.on('click', function(e) {
40385 _t.fireEvent('adderclick', this, e);
40389 //this.adder.on('click', this.onAddClick, _t);
40392 this.combo.on('select', function(cb, rec, ix) {
40393 this.addItem(rec.data);
40396 cb.el.dom.value = '';
40397 //cb.lastData = rec.data;
40406 getName: function()
40408 // returns hidden if it's set..
40409 if (!this.rendered) {return ''};
40410 return this.hiddenName ? this.hiddenName : this.name;
40415 onResize: function(w, h){
40418 // not sure if this is needed..
40419 //this.combo.onResize(w,h);
40421 if(typeof w != 'number'){
40422 // we do not handle it!?!?
40425 var tw = this.combo.trigger.getWidth();
40426 tw += this.addicon ? this.addicon.getWidth() : 0;
40427 tw += this.editicon ? this.editicon.getWidth() : 0;
40429 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40431 this.combo.trigger.setStyle('left', '0px');
40433 if(this.list && this.listWidth === undefined){
40434 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40435 this.list.setWidth(lw);
40436 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40443 addItem: function(rec)
40445 var valueField = this.combo.valueField;
40446 var displayField = this.combo.displayField;
40447 if (this.items.indexOfKey(rec[valueField]) > -1) {
40448 //console.log("GOT " + rec.data.id);
40452 var x = new Roo.form.ComboBoxArray.Item({
40453 //id : rec[this.idField],
40455 displayField : displayField ,
40456 tipField : displayField ,
40460 this.items.add(rec[valueField],x);
40461 // add it before the element..
40462 this.updateHiddenEl();
40463 x.render(this.outerWrap, this.wrap.dom);
40464 // add the image handler..
40467 updateHiddenEl : function()
40470 if (!this.hiddenEl) {
40474 var idField = this.combo.valueField;
40476 this.items.each(function(f) {
40477 ar.push(f.data[idField]);
40480 this.hiddenEl.dom.value = ar.join(',');
40486 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40487 this.items.each(function(f) {
40490 this.el.dom.value = '';
40491 if (this.hiddenEl) {
40492 this.hiddenEl.dom.value = '';
40496 getValue: function()
40498 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40500 setValue: function(v) // not a valid action - must use addItems..
40507 if (this.store.isLocal && (typeof(v) == 'string')) {
40508 // then we can use the store to find the values..
40509 // comma seperated at present.. this needs to allow JSON based encoding..
40510 this.hiddenEl.value = v;
40512 Roo.each(v.split(','), function(k) {
40513 Roo.log("CHECK " + this.valueField + ',' + k);
40514 var li = this.store.query(this.valueField, k);
40519 add[this.valueField] = k;
40520 add[this.displayField] = li.item(0).data[this.displayField];
40526 if (typeof(v) == 'object') {
40527 // then let's assume it's an array of objects..
40528 Roo.each(v, function(l) {
40536 setFromData: function(v)
40538 // this recieves an object, if setValues is called.
40540 this.el.dom.value = v[this.displayField];
40541 this.hiddenEl.dom.value = v[this.valueField];
40542 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40545 var kv = v[this.valueField];
40546 var dv = v[this.displayField];
40547 kv = typeof(kv) != 'string' ? '' : kv;
40548 dv = typeof(dv) != 'string' ? '' : dv;
40551 var keys = kv.split(',');
40552 var display = dv.split(',');
40553 for (var i = 0 ; i < keys.length; i++) {
40556 add[this.valueField] = keys[i];
40557 add[this.displayField] = display[i];
40565 * Validates the combox array value
40566 * @return {Boolean} True if the value is valid, else false
40568 validate : function(){
40569 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40570 this.clearInvalid();
40576 validateValue : function(value){
40577 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40585 isDirty : function() {
40586 if(this.disabled) {
40591 var d = Roo.decode(String(this.originalValue));
40593 return String(this.getValue()) !== String(this.originalValue);
40596 var originalValue = [];
40598 for (var i = 0; i < d.length; i++){
40599 originalValue.push(d[i][this.valueField]);
40602 return String(this.getValue()) !== String(originalValue.join(','));
40611 * @class Roo.form.ComboBoxArray.Item
40612 * @extends Roo.BoxComponent
40613 * A selected item in the list
40614 * Fred [x] Brian [x] [Pick another |v]
40617 * Create a new item.
40618 * @param {Object} config Configuration options
40621 Roo.form.ComboBoxArray.Item = function(config) {
40622 config.id = Roo.id();
40623 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40626 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40629 displayField : false,
40633 defaultAutoCreate : {
40635 cls: 'x-cbarray-item',
40642 src : Roo.BLANK_IMAGE_URL ,
40650 onRender : function(ct, position)
40652 Roo.form.Field.superclass.onRender.call(this, ct, position);
40655 var cfg = this.getAutoCreate();
40656 this.el = ct.createChild(cfg, position);
40659 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40661 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40662 this.cb.renderer(this.data) :
40663 String.format('{0}',this.data[this.displayField]);
40666 this.el.child('div').dom.setAttribute('qtip',
40667 String.format('{0}',this.data[this.tipField])
40670 this.el.child('img').on('click', this.remove, this);
40674 remove : function()
40676 this.cb.items.remove(this);
40677 this.el.child('img').un('click', this.remove, this);
40679 this.cb.updateHiddenEl();
40681 this.cb.fireEvent('remove', this.cb, this);
40685 * Ext JS Library 1.1.1
40686 * Copyright(c) 2006-2007, Ext JS, LLC.
40688 * Originally Released Under LGPL - original licence link has changed is not relivant.
40691 * <script type="text/javascript">
40694 * @class Roo.form.Checkbox
40695 * @extends Roo.form.Field
40696 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40698 * Creates a new Checkbox
40699 * @param {Object} config Configuration options
40701 Roo.form.Checkbox = function(config){
40702 Roo.form.Checkbox.superclass.constructor.call(this, config);
40706 * Fires when the checkbox is checked or unchecked.
40707 * @param {Roo.form.Checkbox} this This checkbox
40708 * @param {Boolean} checked The new checked value
40714 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40716 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40718 focusClass : undefined,
40720 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40722 fieldClass: "x-form-field",
40724 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40728 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40729 * {tag: "input", type: "checkbox", autocomplete: "off"})
40731 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40733 * @cfg {String} boxLabel The text that appears beside the checkbox
40737 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40741 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40743 valueOff: '0', // value when not checked..
40745 actionMode : 'viewEl',
40748 itemCls : 'x-menu-check-item x-form-item',
40749 groupClass : 'x-menu-group-item',
40750 inputType : 'hidden',
40753 inSetChecked: false, // check that we are not calling self...
40755 inputElement: false, // real input element?
40756 basedOn: false, // ????
40758 isFormField: true, // not sure where this is needed!!!!
40760 onResize : function(){
40761 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40762 if(!this.boxLabel){
40763 this.el.alignTo(this.wrap, 'c-c');
40767 initEvents : function(){
40768 Roo.form.Checkbox.superclass.initEvents.call(this);
40769 this.el.on("click", this.onClick, this);
40770 this.el.on("change", this.onClick, this);
40774 getResizeEl : function(){
40778 getPositionEl : function(){
40783 onRender : function(ct, position){
40784 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40786 if(this.inputValue !== undefined){
40787 this.el.dom.value = this.inputValue;
40790 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40791 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40792 var viewEl = this.wrap.createChild({
40793 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40794 this.viewEl = viewEl;
40795 this.wrap.on('click', this.onClick, this);
40797 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40798 this.el.on('propertychange', this.setFromHidden, this); //ie
40803 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40804 // viewEl.on('click', this.onClick, this);
40806 //if(this.checked){
40807 this.setChecked(this.checked);
40809 //this.checked = this.el.dom;
40815 initValue : Roo.emptyFn,
40818 * Returns the checked state of the checkbox.
40819 * @return {Boolean} True if checked, else false
40821 getValue : function(){
40823 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40825 return this.valueOff;
40830 onClick : function(){
40831 this.setChecked(!this.checked);
40833 //if(this.el.dom.checked != this.checked){
40834 // this.setValue(this.el.dom.checked);
40839 * Sets the checked state of the checkbox.
40840 * On is always based on a string comparison between inputValue and the param.
40841 * @param {Boolean/String} value - the value to set
40842 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40844 setValue : function(v,suppressEvent){
40847 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40848 //if(this.el && this.el.dom){
40849 // this.el.dom.checked = this.checked;
40850 // this.el.dom.defaultChecked = this.checked;
40852 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40853 //this.fireEvent("check", this, this.checked);
40856 setChecked : function(state,suppressEvent)
40858 if (this.inSetChecked) {
40859 this.checked = state;
40865 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40867 this.checked = state;
40868 if(suppressEvent !== true){
40869 this.fireEvent('check', this, state);
40871 this.inSetChecked = true;
40872 this.el.dom.value = state ? this.inputValue : this.valueOff;
40873 this.inSetChecked = false;
40876 // handle setting of hidden value by some other method!!?!?
40877 setFromHidden: function()
40882 //console.log("SET FROM HIDDEN");
40883 //alert('setFrom hidden');
40884 this.setValue(this.el.dom.value);
40887 onDestroy : function()
40890 Roo.get(this.viewEl).remove();
40893 Roo.form.Checkbox.superclass.onDestroy.call(this);
40898 * Ext JS Library 1.1.1
40899 * Copyright(c) 2006-2007, Ext JS, LLC.
40901 * Originally Released Under LGPL - original licence link has changed is not relivant.
40904 * <script type="text/javascript">
40908 * @class Roo.form.Radio
40909 * @extends Roo.form.Checkbox
40910 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40911 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40913 * Creates a new Radio
40914 * @param {Object} config Configuration options
40916 Roo.form.Radio = function(){
40917 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40919 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40920 inputType: 'radio',
40923 * If this radio is part of a group, it will return the selected value
40926 getGroupValue : function(){
40927 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40931 onRender : function(ct, position){
40932 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40934 if(this.inputValue !== undefined){
40935 this.el.dom.value = this.inputValue;
40938 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40939 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40940 //var viewEl = this.wrap.createChild({
40941 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40942 //this.viewEl = viewEl;
40943 //this.wrap.on('click', this.onClick, this);
40945 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40946 //this.el.on('propertychange', this.setFromHidden, this); //ie
40951 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40952 // viewEl.on('click', this.onClick, this);
40955 this.el.dom.checked = 'checked' ;
40961 });//<script type="text/javascript">
40964 * Based Ext JS Library 1.1.1
40965 * Copyright(c) 2006-2007, Ext JS, LLC.
40971 * @class Roo.HtmlEditorCore
40972 * @extends Roo.Component
40973 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
40975 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40978 Roo.HtmlEditorCore = function(config){
40981 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
40984 * @event initialize
40985 * Fires when the editor is fully initialized (including the iframe)
40986 * @param {Roo.HtmlEditorCore} this
40991 * Fires when the editor is first receives the focus. Any insertion must wait
40992 * until after this event.
40993 * @param {Roo.HtmlEditorCore} this
40997 * @event beforesync
40998 * Fires before the textarea is updated with content from the editor iframe. Return false
40999 * to cancel the sync.
41000 * @param {Roo.HtmlEditorCore} this
41001 * @param {String} html
41005 * @event beforepush
41006 * Fires before the iframe editor is updated with content from the textarea. Return false
41007 * to cancel the push.
41008 * @param {Roo.HtmlEditorCore} this
41009 * @param {String} html
41014 * Fires when the textarea is updated with content from the editor iframe.
41015 * @param {Roo.HtmlEditorCore} this
41016 * @param {String} html
41021 * Fires when the iframe editor is updated with content from the textarea.
41022 * @param {Roo.HtmlEditorCore} this
41023 * @param {String} html
41028 * @event editorevent
41029 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41030 * @param {Roo.HtmlEditorCore} this
41038 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41042 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41048 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41053 * @cfg {Number} height (in pixels)
41057 * @cfg {Number} width (in pixels)
41062 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41065 stylesheets: false,
41070 // private properties
41071 validationEvent : false,
41073 initialized : false,
41075 sourceEditMode : false,
41076 onFocus : Roo.emptyFn,
41078 hideMode:'offsets',
41086 * Protected method that will not generally be called directly. It
41087 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41088 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41090 getDocMarkup : function(){
41093 Roo.log(this.stylesheets);
41095 // inherit styels from page...??
41096 if (this.stylesheets === false) {
41098 Roo.get(document.head).select('style').each(function(node) {
41099 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41102 Roo.get(document.head).select('link').each(function(node) {
41103 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41106 } else if (!this.stylesheets.length) {
41108 st = '<style type="text/css">' +
41109 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41112 Roo.each(this.stylesheets, function(s) {
41113 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
41118 st += '<style type="text/css">' +
41119 'IMG { cursor: pointer } ' +
41123 return '<html><head>' + st +
41124 //<style type="text/css">' +
41125 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41127 ' </head><body class="roo-htmleditor-body"></body></html>';
41131 onRender : function(ct, position)
41134 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41135 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41138 this.el.dom.style.border = '0 none';
41139 this.el.dom.setAttribute('tabIndex', -1);
41140 this.el.addClass('x-hidden hide');
41144 if(Roo.isIE){ // fix IE 1px bogus margin
41145 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41149 this.frameId = Roo.id();
41153 var iframe = this.owner.wrap.createChild({
41155 cls: 'form-control', // bootstrap..
41157 name: this.frameId,
41158 frameBorder : 'no',
41159 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41164 this.iframe = iframe.dom;
41166 this.assignDocWin();
41168 this.doc.designMode = 'on';
41171 this.doc.write(this.getDocMarkup());
41175 var task = { // must defer to wait for browser to be ready
41177 //console.log("run task?" + this.doc.readyState);
41178 this.assignDocWin();
41179 if(this.doc.body || this.doc.readyState == 'complete'){
41181 this.doc.designMode="on";
41185 Roo.TaskMgr.stop(task);
41186 this.initEditor.defer(10, this);
41193 Roo.TaskMgr.start(task);
41200 onResize : function(w, h)
41202 Roo.log('resize: ' +w + ',' + h );
41203 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41207 if(typeof w == 'number'){
41209 this.iframe.style.width = w + 'px';
41211 if(typeof h == 'number'){
41213 this.iframe.style.height = h + 'px';
41215 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41222 * Toggles the editor between standard and source edit mode.
41223 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41225 toggleSourceEdit : function(sourceEditMode){
41227 this.sourceEditMode = sourceEditMode === true;
41229 if(this.sourceEditMode){
41231 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41234 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41235 //this.iframe.className = '';
41238 //this.setSize(this.owner.wrap.getSize());
41239 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41246 * Protected method that will not generally be called directly. If you need/want
41247 * custom HTML cleanup, this is the method you should override.
41248 * @param {String} html The HTML to be cleaned
41249 * return {String} The cleaned HTML
41251 cleanHtml : function(html){
41252 html = String(html);
41253 if(html.length > 5){
41254 if(Roo.isSafari){ // strip safari nonsense
41255 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41258 if(html == ' '){
41265 * HTML Editor -> Textarea
41266 * Protected method that will not generally be called directly. Syncs the contents
41267 * of the editor iframe with the textarea.
41269 syncValue : function(){
41270 if(this.initialized){
41271 var bd = (this.doc.body || this.doc.documentElement);
41272 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41273 var html = bd.innerHTML;
41275 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41276 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41278 html = '<div style="'+m[0]+'">' + html + '</div>';
41281 html = this.cleanHtml(html);
41282 // fix up the special chars.. normaly like back quotes in word...
41283 // however we do not want to do this with chinese..
41284 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41285 var cc = b.charCodeAt();
41287 (cc >= 0x4E00 && cc < 0xA000 ) ||
41288 (cc >= 0x3400 && cc < 0x4E00 ) ||
41289 (cc >= 0xf900 && cc < 0xfb00 )
41295 if(this.owner.fireEvent('beforesync', this, html) !== false){
41296 this.el.dom.value = html;
41297 this.owner.fireEvent('sync', this, html);
41303 * Protected method that will not generally be called directly. Pushes the value of the textarea
41304 * into the iframe editor.
41306 pushValue : function(){
41307 if(this.initialized){
41308 var v = this.el.dom.value.trim();
41310 // if(v.length < 1){
41314 if(this.owner.fireEvent('beforepush', this, v) !== false){
41315 var d = (this.doc.body || this.doc.documentElement);
41317 this.cleanUpPaste();
41318 this.el.dom.value = d.innerHTML;
41319 this.owner.fireEvent('push', this, v);
41325 deferFocus : function(){
41326 this.focus.defer(10, this);
41330 focus : function(){
41331 if(this.win && !this.sourceEditMode){
41338 assignDocWin: function()
41340 var iframe = this.iframe;
41343 this.doc = iframe.contentWindow.document;
41344 this.win = iframe.contentWindow;
41346 if (!Roo.get(this.frameId)) {
41349 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41350 this.win = Roo.get(this.frameId).dom.contentWindow;
41355 initEditor : function(){
41356 //console.log("INIT EDITOR");
41357 this.assignDocWin();
41361 this.doc.designMode="on";
41363 this.doc.write(this.getDocMarkup());
41366 var dbody = (this.doc.body || this.doc.documentElement);
41367 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41368 // this copies styles from the containing element into thsi one..
41369 // not sure why we need all of this..
41370 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41372 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41373 //ss['background-attachment'] = 'fixed'; // w3c
41374 dbody.bgProperties = 'fixed'; // ie
41375 //Roo.DomHelper.applyStyles(dbody, ss);
41376 Roo.EventManager.on(this.doc, {
41377 //'mousedown': this.onEditorEvent,
41378 'mouseup': this.onEditorEvent,
41379 'dblclick': this.onEditorEvent,
41380 'click': this.onEditorEvent,
41381 'keyup': this.onEditorEvent,
41386 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41388 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41389 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41391 this.initialized = true;
41393 this.owner.fireEvent('initialize', this);
41398 onDestroy : function(){
41404 //for (var i =0; i < this.toolbars.length;i++) {
41405 // // fixme - ask toolbars for heights?
41406 // this.toolbars[i].onDestroy();
41409 //this.wrap.dom.innerHTML = '';
41410 //this.wrap.remove();
41415 onFirstFocus : function(){
41417 this.assignDocWin();
41420 this.activated = true;
41423 if(Roo.isGecko){ // prevent silly gecko errors
41425 var s = this.win.getSelection();
41426 if(!s.focusNode || s.focusNode.nodeType != 3){
41427 var r = s.getRangeAt(0);
41428 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41433 this.execCmd('useCSS', true);
41434 this.execCmd('styleWithCSS', false);
41437 this.owner.fireEvent('activate', this);
41441 adjustFont: function(btn){
41442 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41443 //if(Roo.isSafari){ // safari
41446 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41447 if(Roo.isSafari){ // safari
41448 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41449 v = (v < 10) ? 10 : v;
41450 v = (v > 48) ? 48 : v;
41451 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41456 v = Math.max(1, v+adjust);
41458 this.execCmd('FontSize', v );
41461 onEditorEvent : function(e){
41462 this.owner.fireEvent('editorevent', this, e);
41463 // this.updateToolbar();
41464 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41467 insertTag : function(tg)
41469 // could be a bit smarter... -> wrap the current selected tRoo..
41470 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41472 range = this.createRange(this.getSelection());
41473 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41474 wrappingNode.appendChild(range.extractContents());
41475 range.insertNode(wrappingNode);
41482 this.execCmd("formatblock", tg);
41486 insertText : function(txt)
41490 var range = this.createRange();
41491 range.deleteContents();
41492 //alert(Sender.getAttribute('label'));
41494 range.insertNode(this.doc.createTextNode(txt));
41500 * Executes a Midas editor command on the editor document and performs necessary focus and
41501 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41502 * @param {String} cmd The Midas command
41503 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41505 relayCmd : function(cmd, value){
41507 this.execCmd(cmd, value);
41508 this.owner.fireEvent('editorevent', this);
41509 //this.updateToolbar();
41510 this.owner.deferFocus();
41514 * Executes a Midas editor command directly on the editor document.
41515 * For visual commands, you should use {@link #relayCmd} instead.
41516 * <b>This should only be called after the editor is initialized.</b>
41517 * @param {String} cmd The Midas command
41518 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41520 execCmd : function(cmd, value){
41521 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41528 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41530 * @param {String} text | dom node..
41532 insertAtCursor : function(text)
41537 if(!this.activated){
41543 var r = this.doc.selection.createRange();
41554 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41558 // from jquery ui (MIT licenced)
41560 var win = this.win;
41562 if (win.getSelection && win.getSelection().getRangeAt) {
41563 range = win.getSelection().getRangeAt(0);
41564 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41565 range.insertNode(node);
41566 } else if (win.document.selection && win.document.selection.createRange) {
41567 // no firefox support
41568 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41569 win.document.selection.createRange().pasteHTML(txt);
41571 // no firefox support
41572 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41573 this.execCmd('InsertHTML', txt);
41582 mozKeyPress : function(e){
41584 var c = e.getCharCode(), cmd;
41587 c = String.fromCharCode(c).toLowerCase();
41601 this.cleanUpPaste.defer(100, this);
41609 e.preventDefault();
41617 fixKeys : function(){ // load time branching for fastest keydown performance
41619 return function(e){
41620 var k = e.getKey(), r;
41623 r = this.doc.selection.createRange();
41626 r.pasteHTML('    ');
41633 r = this.doc.selection.createRange();
41635 var target = r.parentElement();
41636 if(!target || target.tagName.toLowerCase() != 'li'){
41638 r.pasteHTML('<br />');
41644 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41645 this.cleanUpPaste.defer(100, this);
41651 }else if(Roo.isOpera){
41652 return function(e){
41653 var k = e.getKey();
41657 this.execCmd('InsertHTML','    ');
41660 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41661 this.cleanUpPaste.defer(100, this);
41666 }else if(Roo.isSafari){
41667 return function(e){
41668 var k = e.getKey();
41672 this.execCmd('InsertText','\t');
41676 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41677 this.cleanUpPaste.defer(100, this);
41685 getAllAncestors: function()
41687 var p = this.getSelectedNode();
41690 a.push(p); // push blank onto stack..
41691 p = this.getParentElement();
41695 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41699 a.push(this.doc.body);
41703 lastSelNode : false,
41706 getSelection : function()
41708 this.assignDocWin();
41709 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41712 getSelectedNode: function()
41714 // this may only work on Gecko!!!
41716 // should we cache this!!!!
41721 var range = this.createRange(this.getSelection()).cloneRange();
41724 var parent = range.parentElement();
41726 var testRange = range.duplicate();
41727 testRange.moveToElementText(parent);
41728 if (testRange.inRange(range)) {
41731 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41734 parent = parent.parentElement;
41739 // is ancestor a text element.
41740 var ac = range.commonAncestorContainer;
41741 if (ac.nodeType == 3) {
41742 ac = ac.parentNode;
41745 var ar = ac.childNodes;
41748 var other_nodes = [];
41749 var has_other_nodes = false;
41750 for (var i=0;i<ar.length;i++) {
41751 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41754 // fullly contained node.
41756 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41761 // probably selected..
41762 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41763 other_nodes.push(ar[i]);
41767 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41772 has_other_nodes = true;
41774 if (!nodes.length && other_nodes.length) {
41775 nodes= other_nodes;
41777 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41783 createRange: function(sel)
41785 // this has strange effects when using with
41786 // top toolbar - not sure if it's a great idea.
41787 //this.editor.contentWindow.focus();
41788 if (typeof sel != "undefined") {
41790 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41792 return this.doc.createRange();
41795 return this.doc.createRange();
41798 getParentElement: function()
41801 this.assignDocWin();
41802 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41804 var range = this.createRange(sel);
41807 var p = range.commonAncestorContainer;
41808 while (p.nodeType == 3) { // text node
41819 * Range intersection.. the hard stuff...
41823 * [ -- selected range --- ]
41827 * if end is before start or hits it. fail.
41828 * if start is after end or hits it fail.
41830 * if either hits (but other is outside. - then it's not
41836 // @see http://www.thismuchiknow.co.uk/?p=64.
41837 rangeIntersectsNode : function(range, node)
41839 var nodeRange = node.ownerDocument.createRange();
41841 nodeRange.selectNode(node);
41843 nodeRange.selectNodeContents(node);
41846 var rangeStartRange = range.cloneRange();
41847 rangeStartRange.collapse(true);
41849 var rangeEndRange = range.cloneRange();
41850 rangeEndRange.collapse(false);
41852 var nodeStartRange = nodeRange.cloneRange();
41853 nodeStartRange.collapse(true);
41855 var nodeEndRange = nodeRange.cloneRange();
41856 nodeEndRange.collapse(false);
41858 return rangeStartRange.compareBoundaryPoints(
41859 Range.START_TO_START, nodeEndRange) == -1 &&
41860 rangeEndRange.compareBoundaryPoints(
41861 Range.START_TO_START, nodeStartRange) == 1;
41865 rangeCompareNode : function(range, node)
41867 var nodeRange = node.ownerDocument.createRange();
41869 nodeRange.selectNode(node);
41871 nodeRange.selectNodeContents(node);
41875 range.collapse(true);
41877 nodeRange.collapse(true);
41879 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41880 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41882 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41884 var nodeIsBefore = ss == 1;
41885 var nodeIsAfter = ee == -1;
41887 if (nodeIsBefore && nodeIsAfter)
41889 if (!nodeIsBefore && nodeIsAfter)
41890 return 1; //right trailed.
41892 if (nodeIsBefore && !nodeIsAfter)
41893 return 2; // left trailed.
41898 // private? - in a new class?
41899 cleanUpPaste : function()
41901 // cleans up the whole document..
41902 Roo.log('cleanuppaste');
41904 this.cleanUpChildren(this.doc.body);
41905 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41906 if (clean != this.doc.body.innerHTML) {
41907 this.doc.body.innerHTML = clean;
41912 cleanWordChars : function(input) {// change the chars to hex code
41913 var he = Roo.HtmlEditorCore;
41915 var output = input;
41916 Roo.each(he.swapCodes, function(sw) {
41917 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41919 output = output.replace(swapper, sw[1]);
41926 cleanUpChildren : function (n)
41928 if (!n.childNodes.length) {
41931 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41932 this.cleanUpChild(n.childNodes[i]);
41939 cleanUpChild : function (node)
41942 //console.log(node);
41943 if (node.nodeName == "#text") {
41944 // clean up silly Windows -- stuff?
41947 if (node.nodeName == "#comment") {
41948 node.parentNode.removeChild(node);
41949 // clean up silly Windows -- stuff?
41953 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
41955 node.parentNode.removeChild(node);
41960 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
41962 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41963 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41965 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41966 // remove_keep_children = true;
41969 if (remove_keep_children) {
41970 this.cleanUpChildren(node);
41971 // inserts everything just before this node...
41972 while (node.childNodes.length) {
41973 var cn = node.childNodes[0];
41974 node.removeChild(cn);
41975 node.parentNode.insertBefore(cn, node);
41977 node.parentNode.removeChild(node);
41981 if (!node.attributes || !node.attributes.length) {
41982 this.cleanUpChildren(node);
41986 function cleanAttr(n,v)
41989 if (v.match(/^\./) || v.match(/^\//)) {
41992 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41995 if (v.match(/^#/)) {
41998 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41999 node.removeAttribute(n);
42003 function cleanStyle(n,v)
42005 if (v.match(/expression/)) { //XSS?? should we even bother..
42006 node.removeAttribute(n);
42009 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
42010 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
42013 var parts = v.split(/;/);
42016 Roo.each(parts, function(p) {
42017 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42021 var l = p.split(':').shift().replace(/\s+/g,'');
42022 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42024 if ( cblack.indexOf(l) > -1) {
42025 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42026 //node.removeAttribute(n);
42030 // only allow 'c whitelisted system attributes'
42031 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42032 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42033 //node.removeAttribute(n);
42043 if (clean.length) {
42044 node.setAttribute(n, clean.join(';'));
42046 node.removeAttribute(n);
42052 for (var i = node.attributes.length-1; i > -1 ; i--) {
42053 var a = node.attributes[i];
42056 if (a.name.toLowerCase().substr(0,2)=='on') {
42057 node.removeAttribute(a.name);
42060 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42061 node.removeAttribute(a.name);
42064 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42065 cleanAttr(a.name,a.value); // fixme..
42068 if (a.name == 'style') {
42069 cleanStyle(a.name,a.value);
42072 /// clean up MS crap..
42073 // tecnically this should be a list of valid class'es..
42076 if (a.name == 'class') {
42077 if (a.value.match(/^Mso/)) {
42078 node.className = '';
42081 if (a.value.match(/body/)) {
42082 node.className = '';
42093 this.cleanUpChildren(node);
42098 * Clean up MS wordisms...
42100 cleanWord : function(node)
42103 var cleanWordChildren = function()
42105 if (!node.childNodes.length) {
42108 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42109 _t.cleanWord(node.childNodes[i]);
42115 this.cleanWord(this.doc.body);
42118 if (node.nodeName == "#text") {
42119 // clean up silly Windows -- stuff?
42122 if (node.nodeName == "#comment") {
42123 node.parentNode.removeChild(node);
42124 // clean up silly Windows -- stuff?
42128 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42129 node.parentNode.removeChild(node);
42133 // remove - but keep children..
42134 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42135 while (node.childNodes.length) {
42136 var cn = node.childNodes[0];
42137 node.removeChild(cn);
42138 node.parentNode.insertBefore(cn, node);
42140 node.parentNode.removeChild(node);
42141 cleanWordChildren();
42145 if (node.className.length) {
42147 var cn = node.className.split(/\W+/);
42149 Roo.each(cn, function(cls) {
42150 if (cls.match(/Mso[a-zA-Z]+/)) {
42155 node.className = cna.length ? cna.join(' ') : '';
42157 node.removeAttribute("class");
42161 if (node.hasAttribute("lang")) {
42162 node.removeAttribute("lang");
42165 if (node.hasAttribute("style")) {
42167 var styles = node.getAttribute("style").split(";");
42169 Roo.each(styles, function(s) {
42170 if (!s.match(/:/)) {
42173 var kv = s.split(":");
42174 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42177 // what ever is left... we allow.
42180 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42181 if (!nstyle.length) {
42182 node.removeAttribute('style');
42186 cleanWordChildren();
42190 domToHTML : function(currentElement, depth, nopadtext) {
42192 depth = depth || 0;
42193 nopadtext = nopadtext || false;
42195 if (!currentElement) {
42196 return this.domToHTML(this.doc.body);
42199 //Roo.log(currentElement);
42201 var allText = false;
42202 var nodeName = currentElement.nodeName;
42203 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42205 if (nodeName == '#text') {
42206 return currentElement.nodeValue;
42211 if (nodeName != 'BODY') {
42214 // Prints the node tagName, such as <A>, <IMG>, etc
42217 for(i = 0; i < currentElement.attributes.length;i++) {
42219 var aname = currentElement.attributes.item(i).name;
42220 if (!currentElement.attributes.item(i).value.length) {
42223 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42226 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42235 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42238 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42243 // Traverse the tree
42245 var currentElementChild = currentElement.childNodes.item(i);
42246 var allText = true;
42247 var innerHTML = '';
42249 while (currentElementChild) {
42250 // Formatting code (indent the tree so it looks nice on the screen)
42251 var nopad = nopadtext;
42252 if (lastnode == 'SPAN') {
42256 if (currentElementChild.nodeName == '#text') {
42257 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42258 if (!nopad && toadd.length > 80) {
42259 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42261 innerHTML += toadd;
42264 currentElementChild = currentElement.childNodes.item(i);
42270 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42272 // Recursively traverse the tree structure of the child node
42273 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42274 lastnode = currentElementChild.nodeName;
42276 currentElementChild=currentElement.childNodes.item(i);
42282 // The remaining code is mostly for formatting the tree
42283 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42288 ret+= "</"+tagName+">";
42294 // hide stuff that is not compatible
42308 * @event specialkey
42312 * @cfg {String} fieldClass @hide
42315 * @cfg {String} focusClass @hide
42318 * @cfg {String} autoCreate @hide
42321 * @cfg {String} inputType @hide
42324 * @cfg {String} invalidClass @hide
42327 * @cfg {String} invalidText @hide
42330 * @cfg {String} msgFx @hide
42333 * @cfg {String} validateOnBlur @hide
42337 Roo.HtmlEditorCore.white = [
42338 'area', 'br', 'img', 'input', 'hr', 'wbr',
42340 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42341 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42342 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42343 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42344 'table', 'ul', 'xmp',
42346 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42349 'dir', 'menu', 'ol', 'ul', 'dl',
42355 Roo.HtmlEditorCore.black = [
42356 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42358 'base', 'basefont', 'bgsound', 'blink', 'body',
42359 'frame', 'frameset', 'head', 'html', 'ilayer',
42360 'iframe', 'layer', 'link', 'meta', 'object',
42361 'script', 'style' ,'title', 'xml' // clean later..
42363 Roo.HtmlEditorCore.clean = [
42364 'script', 'style', 'title', 'xml'
42366 Roo.HtmlEditorCore.remove = [
42371 Roo.HtmlEditorCore.ablack = [
42375 Roo.HtmlEditorCore.aclean = [
42376 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42380 Roo.HtmlEditorCore.pwhite= [
42381 'http', 'https', 'mailto'
42384 // white listed style attributes.
42385 Roo.HtmlEditorCore.cwhite= [
42386 // 'text-align', /// default is to allow most things..
42392 // black listed style attributes.
42393 Roo.HtmlEditorCore.cblack= [
42394 // 'font-size' -- this can be set by the project
42398 Roo.HtmlEditorCore.swapCodes =[
42409 //<script type="text/javascript">
42412 * Ext JS Library 1.1.1
42413 * Copyright(c) 2006-2007, Ext JS, LLC.
42419 Roo.form.HtmlEditor = function(config){
42423 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42425 if (!this.toolbars) {
42426 this.toolbars = [];
42428 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42434 * @class Roo.form.HtmlEditor
42435 * @extends Roo.form.Field
42436 * Provides a lightweight HTML Editor component.
42438 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42440 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42441 * supported by this editor.</b><br/><br/>
42442 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42443 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42445 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42447 * @cfg {Boolean} clearUp
42451 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42456 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42461 * @cfg {Number} height (in pixels)
42465 * @cfg {Number} width (in pixels)
42470 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42473 stylesheets: false,
42478 // private properties
42479 validationEvent : false,
42481 initialized : false,
42484 onFocus : Roo.emptyFn,
42486 hideMode:'offsets',
42488 defaultAutoCreate : { // modified by initCompnoent..
42490 style:"width:500px;height:300px;",
42491 autocomplete: "off"
42495 initComponent : function(){
42498 * @event initialize
42499 * Fires when the editor is fully initialized (including the iframe)
42500 * @param {HtmlEditor} this
42505 * Fires when the editor is first receives the focus. Any insertion must wait
42506 * until after this event.
42507 * @param {HtmlEditor} this
42511 * @event beforesync
42512 * Fires before the textarea is updated with content from the editor iframe. Return false
42513 * to cancel the sync.
42514 * @param {HtmlEditor} this
42515 * @param {String} html
42519 * @event beforepush
42520 * Fires before the iframe editor is updated with content from the textarea. Return false
42521 * to cancel the push.
42522 * @param {HtmlEditor} this
42523 * @param {String} html
42528 * Fires when the textarea is updated with content from the editor iframe.
42529 * @param {HtmlEditor} this
42530 * @param {String} html
42535 * Fires when the iframe editor is updated with content from the textarea.
42536 * @param {HtmlEditor} this
42537 * @param {String} html
42541 * @event editmodechange
42542 * Fires when the editor switches edit modes
42543 * @param {HtmlEditor} this
42544 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42546 editmodechange: true,
42548 * @event editorevent
42549 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42550 * @param {HtmlEditor} this
42554 * @event firstfocus
42555 * Fires when on first focus - needed by toolbars..
42556 * @param {HtmlEditor} this
42561 * Auto save the htmlEditor value as a file into Events
42562 * @param {HtmlEditor} this
42566 * @event savedpreview
42567 * preview the saved version of htmlEditor
42568 * @param {HtmlEditor} this
42572 this.defaultAutoCreate = {
42574 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42575 autocomplete: "off"
42580 * Protected method that will not generally be called directly. It
42581 * is called when the editor creates its toolbar. Override this method if you need to
42582 * add custom toolbar buttons.
42583 * @param {HtmlEditor} editor
42585 createToolbar : function(editor){
42586 Roo.log("create toolbars");
42587 if (!editor.toolbars || !editor.toolbars.length) {
42588 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42591 for (var i =0 ; i < editor.toolbars.length;i++) {
42592 editor.toolbars[i] = Roo.factory(
42593 typeof(editor.toolbars[i]) == 'string' ?
42594 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42595 Roo.form.HtmlEditor);
42596 editor.toolbars[i].init(editor);
42604 onRender : function(ct, position)
42607 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
42609 this.wrap = this.el.wrap({
42610 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
42613 this.editorcore.onRender(ct, position);
42615 if (this.resizable) {
42616 this.resizeEl = new Roo.Resizable(this.wrap, {
42620 minHeight : this.height,
42621 height: this.height,
42622 handles : this.resizable,
42625 resize : function(r, w, h) {
42626 _t.onResize(w,h); // -something
42632 this.createToolbar(this);
42636 this.setSize(this.wrap.getSize());
42638 if (this.resizeEl) {
42639 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
42640 // should trigger onReize..
42643 // if(this.autosave && this.w){
42644 // this.autoSaveFn = setInterval(this.autosave, 1000);
42649 onResize : function(w, h)
42651 //Roo.log('resize: ' +w + ',' + h );
42652 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
42657 if(typeof w == 'number'){
42658 var aw = w - this.wrap.getFrameWidth('lr');
42659 this.el.setWidth(this.adjustWidth('textarea', aw));
42662 if(typeof h == 'number'){
42664 for (var i =0; i < this.toolbars.length;i++) {
42665 // fixme - ask toolbars for heights?
42666 tbh += this.toolbars[i].tb.el.getHeight();
42667 if (this.toolbars[i].footer) {
42668 tbh += this.toolbars[i].footer.el.getHeight();
42675 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
42676 ah -= 5; // knock a few pixes off for look..
42677 this.el.setHeight(this.adjustWidth('textarea', ah));
42681 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
42682 this.editorcore.onResize(ew,eh);
42687 * Toggles the editor between standard and source edit mode.
42688 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42690 toggleSourceEdit : function(sourceEditMode)
42692 this.editorcore.toggleSourceEdit(sourceEditMode);
42694 if(this.editorcore.sourceEditMode){
42695 Roo.log('editor - showing textarea');
42698 // Roo.log(this.syncValue());
42699 this.editorcore.syncValue();
42700 this.el.removeClass('x-hidden');
42701 this.el.dom.removeAttribute('tabIndex');
42704 Roo.log('editor - hiding textarea');
42706 // Roo.log(this.pushValue());
42707 this.editorcore.pushValue();
42709 this.el.addClass('x-hidden');
42710 this.el.dom.setAttribute('tabIndex', -1);
42711 //this.deferFocus();
42714 this.setSize(this.wrap.getSize());
42715 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
42718 // private (for BoxComponent)
42719 adjustSize : Roo.BoxComponent.prototype.adjustSize,
42721 // private (for BoxComponent)
42722 getResizeEl : function(){
42726 // private (for BoxComponent)
42727 getPositionEl : function(){
42732 initEvents : function(){
42733 this.originalValue = this.getValue();
42737 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42740 markInvalid : Roo.emptyFn,
42742 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42745 clearInvalid : Roo.emptyFn,
42747 setValue : function(v){
42748 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
42749 this.editorcore.pushValue();
42754 deferFocus : function(){
42755 this.focus.defer(10, this);
42759 focus : function(){
42760 this.editorcore.focus();
42766 onDestroy : function(){
42772 for (var i =0; i < this.toolbars.length;i++) {
42773 // fixme - ask toolbars for heights?
42774 this.toolbars[i].onDestroy();
42777 this.wrap.dom.innerHTML = '';
42778 this.wrap.remove();
42783 onFirstFocus : function(){
42784 //Roo.log("onFirstFocus");
42785 this.editorcore.onFirstFocus();
42786 for (var i =0; i < this.toolbars.length;i++) {
42787 this.toolbars[i].onFirstFocus();
42793 syncValue : function()
42795 this.editorcore.syncValue();
42798 pushValue : function()
42800 this.editorcore.pushValue();
42804 // hide stuff that is not compatible
42818 * @event specialkey
42822 * @cfg {String} fieldClass @hide
42825 * @cfg {String} focusClass @hide
42828 * @cfg {String} autoCreate @hide
42831 * @cfg {String} inputType @hide
42834 * @cfg {String} invalidClass @hide
42837 * @cfg {String} invalidText @hide
42840 * @cfg {String} msgFx @hide
42843 * @cfg {String} validateOnBlur @hide
42847 // <script type="text/javascript">
42850 * Ext JS Library 1.1.1
42851 * Copyright(c) 2006-2007, Ext JS, LLC.
42857 * @class Roo.form.HtmlEditorToolbar1
42862 new Roo.form.HtmlEditor({
42865 new Roo.form.HtmlEditorToolbar1({
42866 disable : { fonts: 1 , format: 1, ..., ... , ...],
42872 * @cfg {Object} disable List of elements to disable..
42873 * @cfg {Array} btns List of additional buttons.
42877 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
42880 Roo.form.HtmlEditor.ToolbarStandard = function(config)
42883 Roo.apply(this, config);
42885 // default disabled, based on 'good practice'..
42886 this.disable = this.disable || {};
42887 Roo.applyIf(this.disable, {
42890 specialElements : true
42894 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42895 // dont call parent... till later.
42898 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
42905 editorcore : false,
42907 * @cfg {Object} disable List of toolbar elements to disable
42914 * @cfg {String} createLinkText The default text for the create link prompt
42916 createLinkText : 'Please enter the URL for the link:',
42918 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
42920 defaultLinkValue : 'http:/'+'/',
42924 * @cfg {Array} fontFamilies An array of available font families
42942 // "á" , ?? a acute?
42947 "°" // , // degrees
42949 // "é" , // e ecute
42950 // "ú" , // u ecute?
42953 specialElements : [
42955 text: "Insert Table",
42958 ihtml : '<table><tr><td>Cell</td></tr></table>'
42962 text: "Insert Image",
42965 ihtml : '<img src="about:blank"/>'
42974 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
42975 "input:submit", "input:button", "select", "textarea", "label" ],
42978 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
42980 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
42988 * @cfg {String} defaultFont default font to use.
42990 defaultFont: 'tahoma',
42992 fontSelect : false,
42995 formatCombo : false,
42997 init : function(editor)
42999 this.editor = editor;
43000 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43001 var editorcore = this.editorcore;
43005 var fid = editorcore.frameId;
43007 function btn(id, toggle, handler){
43008 var xid = fid + '-'+ id ;
43012 cls : 'x-btn-icon x-edit-'+id,
43013 enableToggle:toggle !== false,
43014 scope: _t, // was editor...
43015 handler:handler||_t.relayBtnCmd,
43016 clickEvent:'mousedown',
43017 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43024 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43026 // stop form submits
43027 tb.el.on('click', function(e){
43028 e.preventDefault(); // what does this do?
43031 if(!this.disable.font) { // && !Roo.isSafari){
43032 /* why no safari for fonts
43033 editor.fontSelect = tb.el.createChild({
43036 cls:'x-font-select',
43037 html: this.createFontOptions()
43040 editor.fontSelect.on('change', function(){
43041 var font = editor.fontSelect.dom.value;
43042 editor.relayCmd('fontname', font);
43043 editor.deferFocus();
43047 editor.fontSelect.dom,
43053 if(!this.disable.formats){
43054 this.formatCombo = new Roo.form.ComboBox({
43055 store: new Roo.data.SimpleStore({
43058 data : this.formats // from states.js
43062 //autoCreate : {tag: "div", size: "20"},
43063 displayField:'tag',
43067 triggerAction: 'all',
43068 emptyText:'Add tag',
43069 selectOnFocus:true,
43072 'select': function(c, r, i) {
43073 editorcore.insertTag(r.get('tag'));
43079 tb.addField(this.formatCombo);
43083 if(!this.disable.format){
43090 if(!this.disable.fontSize){
43095 btn('increasefontsize', false, editorcore.adjustFont),
43096 btn('decreasefontsize', false, editorcore.adjustFont)
43101 if(!this.disable.colors){
43104 id:editorcore.frameId +'-forecolor',
43105 cls:'x-btn-icon x-edit-forecolor',
43106 clickEvent:'mousedown',
43107 tooltip: this.buttonTips['forecolor'] || undefined,
43109 menu : new Roo.menu.ColorMenu({
43110 allowReselect: true,
43111 focus: Roo.emptyFn,
43114 selectHandler: function(cp, color){
43115 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43116 editor.deferFocus();
43119 clickEvent:'mousedown'
43122 id:editorcore.frameId +'backcolor',
43123 cls:'x-btn-icon x-edit-backcolor',
43124 clickEvent:'mousedown',
43125 tooltip: this.buttonTips['backcolor'] || undefined,
43127 menu : new Roo.menu.ColorMenu({
43128 focus: Roo.emptyFn,
43131 allowReselect: true,
43132 selectHandler: function(cp, color){
43134 editorcore.execCmd('useCSS', false);
43135 editorcore.execCmd('hilitecolor', color);
43136 editorcore.execCmd('useCSS', true);
43137 editor.deferFocus();
43139 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43140 Roo.isSafari || Roo.isIE ? '#'+color : color);
43141 editor.deferFocus();
43145 clickEvent:'mousedown'
43150 // now add all the items...
43153 if(!this.disable.alignments){
43156 btn('justifyleft'),
43157 btn('justifycenter'),
43158 btn('justifyright')
43162 //if(!Roo.isSafari){
43163 if(!this.disable.links){
43166 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43170 if(!this.disable.lists){
43173 btn('insertorderedlist'),
43174 btn('insertunorderedlist')
43177 if(!this.disable.sourceEdit){
43180 btn('sourceedit', true, function(btn){
43182 this.toggleSourceEdit(btn.pressed);
43189 // special menu.. - needs to be tidied up..
43190 if (!this.disable.special) {
43193 cls: 'x-edit-none',
43199 for (var i =0; i < this.specialChars.length; i++) {
43200 smenu.menu.items.push({
43202 html: this.specialChars[i],
43203 handler: function(a,b) {
43204 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43205 //editor.insertAtCursor(a.html);
43219 if (!this.disable.cleanStyles) {
43221 cls: 'x-btn-icon x-btn-clear',
43227 for (var i =0; i < this.cleanStyles.length; i++) {
43228 cmenu.menu.items.push({
43229 actiontype : this.cleanStyles[i],
43230 html: 'Remove ' + this.cleanStyles[i],
43231 handler: function(a,b) {
43234 var c = Roo.get(editorcore.doc.body);
43235 c.select('[style]').each(function(s) {
43236 s.dom.style.removeProperty(a.actiontype);
43238 editorcore.syncValue();
43243 cmenu.menu.items.push({
43244 actiontype : 'word',
43245 html: 'Remove MS Word Formating',
43246 handler: function(a,b) {
43247 editorcore.cleanWord();
43248 editorcore.syncValue();
43253 cmenu.menu.items.push({
43254 actiontype : 'all',
43255 html: 'Remove All Styles',
43256 handler: function(a,b) {
43258 var c = Roo.get(editorcore.doc.body);
43259 c.select('[style]').each(function(s) {
43260 s.dom.removeAttribute('style');
43262 editorcore.syncValue();
43266 cmenu.menu.items.push({
43267 actiontype : 'word',
43268 html: 'Tidy HTML Source',
43269 handler: function(a,b) {
43270 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43271 editorcore.syncValue();
43280 if (!this.disable.specialElements) {
43283 cls: 'x-edit-none',
43288 for (var i =0; i < this.specialElements.length; i++) {
43289 semenu.menu.items.push(
43291 handler: function(a,b) {
43292 editor.insertAtCursor(this.ihtml);
43294 }, this.specialElements[i])
43306 for(var i =0; i< this.btns.length;i++) {
43307 var b = Roo.factory(this.btns[i],Roo.form);
43308 b.cls = 'x-edit-none';
43309 b.scope = editorcore;
43317 // disable everything...
43319 this.tb.items.each(function(item){
43320 if(item.id != editorcore.frameId+ '-sourceedit'){
43324 this.rendered = true;
43326 // the all the btns;
43327 editor.on('editorevent', this.updateToolbar, this);
43328 // other toolbars need to implement this..
43329 //editor.on('editmodechange', this.updateToolbar, this);
43333 relayBtnCmd : function(btn) {
43334 this.editorcore.relayCmd(btn.cmd);
43336 // private used internally
43337 createLink : function(){
43338 Roo.log("create link?");
43339 var url = prompt(this.createLinkText, this.defaultLinkValue);
43340 if(url && url != 'http:/'+'/'){
43341 this.editorcore.relayCmd('createlink', url);
43347 * Protected method that will not generally be called directly. It triggers
43348 * a toolbar update by reading the markup state of the current selection in the editor.
43350 updateToolbar: function(){
43352 if(!this.editorcore.activated){
43353 this.editor.onFirstFocus();
43357 var btns = this.tb.items.map,
43358 doc = this.editorcore.doc,
43359 frameId = this.editorcore.frameId;
43361 if(!this.disable.font && !Roo.isSafari){
43363 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43364 if(name != this.fontSelect.dom.value){
43365 this.fontSelect.dom.value = name;
43369 if(!this.disable.format){
43370 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43371 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43372 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43374 if(!this.disable.alignments){
43375 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43376 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43377 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43379 if(!Roo.isSafari && !this.disable.lists){
43380 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43381 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43384 var ans = this.editorcore.getAllAncestors();
43385 if (this.formatCombo) {
43388 var store = this.formatCombo.store;
43389 this.formatCombo.setValue("");
43390 for (var i =0; i < ans.length;i++) {
43391 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43393 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43401 // hides menus... - so this cant be on a menu...
43402 Roo.menu.MenuMgr.hideAll();
43404 //this.editorsyncValue();
43408 createFontOptions : function(){
43409 var buf = [], fs = this.fontFamilies, ff, lc;
43413 for(var i = 0, len = fs.length; i< len; i++){
43415 lc = ff.toLowerCase();
43417 '<option value="',lc,'" style="font-family:',ff,';"',
43418 (this.defaultFont == lc ? ' selected="true">' : '>'),
43423 return buf.join('');
43426 toggleSourceEdit : function(sourceEditMode){
43428 Roo.log("toolbar toogle");
43429 if(sourceEditMode === undefined){
43430 sourceEditMode = !this.sourceEditMode;
43432 this.sourceEditMode = sourceEditMode === true;
43433 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43434 // just toggle the button?
43435 if(btn.pressed !== this.sourceEditMode){
43436 btn.toggle(this.sourceEditMode);
43440 if(sourceEditMode){
43441 Roo.log("disabling buttons");
43442 this.tb.items.each(function(item){
43443 if(item.cmd != 'sourceedit'){
43449 Roo.log("enabling buttons");
43450 if(this.editorcore.initialized){
43451 this.tb.items.each(function(item){
43457 Roo.log("calling toggole on editor");
43458 // tell the editor that it's been pressed..
43459 this.editor.toggleSourceEdit(sourceEditMode);
43463 * Object collection of toolbar tooltips for the buttons in the editor. The key
43464 * is the command id associated with that button and the value is a valid QuickTips object.
43469 title: 'Bold (Ctrl+B)',
43470 text: 'Make the selected text bold.',
43471 cls: 'x-html-editor-tip'
43474 title: 'Italic (Ctrl+I)',
43475 text: 'Make the selected text italic.',
43476 cls: 'x-html-editor-tip'
43484 title: 'Bold (Ctrl+B)',
43485 text: 'Make the selected text bold.',
43486 cls: 'x-html-editor-tip'
43489 title: 'Italic (Ctrl+I)',
43490 text: 'Make the selected text italic.',
43491 cls: 'x-html-editor-tip'
43494 title: 'Underline (Ctrl+U)',
43495 text: 'Underline the selected text.',
43496 cls: 'x-html-editor-tip'
43498 increasefontsize : {
43499 title: 'Grow Text',
43500 text: 'Increase the font size.',
43501 cls: 'x-html-editor-tip'
43503 decreasefontsize : {
43504 title: 'Shrink Text',
43505 text: 'Decrease the font size.',
43506 cls: 'x-html-editor-tip'
43509 title: 'Text Highlight Color',
43510 text: 'Change the background color of the selected text.',
43511 cls: 'x-html-editor-tip'
43514 title: 'Font Color',
43515 text: 'Change the color of the selected text.',
43516 cls: 'x-html-editor-tip'
43519 title: 'Align Text Left',
43520 text: 'Align text to the left.',
43521 cls: 'x-html-editor-tip'
43524 title: 'Center Text',
43525 text: 'Center text in the editor.',
43526 cls: 'x-html-editor-tip'
43529 title: 'Align Text Right',
43530 text: 'Align text to the right.',
43531 cls: 'x-html-editor-tip'
43533 insertunorderedlist : {
43534 title: 'Bullet List',
43535 text: 'Start a bulleted list.',
43536 cls: 'x-html-editor-tip'
43538 insertorderedlist : {
43539 title: 'Numbered List',
43540 text: 'Start a numbered list.',
43541 cls: 'x-html-editor-tip'
43544 title: 'Hyperlink',
43545 text: 'Make the selected text a hyperlink.',
43546 cls: 'x-html-editor-tip'
43549 title: 'Source Edit',
43550 text: 'Switch to source editing mode.',
43551 cls: 'x-html-editor-tip'
43555 onDestroy : function(){
43558 this.tb.items.each(function(item){
43560 item.menu.removeAll();
43562 item.menu.el.destroy();
43570 onFirstFocus: function() {
43571 this.tb.items.each(function(item){
43580 // <script type="text/javascript">
43583 * Ext JS Library 1.1.1
43584 * Copyright(c) 2006-2007, Ext JS, LLC.
43591 * @class Roo.form.HtmlEditor.ToolbarContext
43596 new Roo.form.HtmlEditor({
43599 { xtype: 'ToolbarStandard', styles : {} }
43600 { xtype: 'ToolbarContext', disable : {} }
43606 * @config : {Object} disable List of elements to disable.. (not done yet.)
43607 * @config : {Object} styles Map of styles available.
43611 Roo.form.HtmlEditor.ToolbarContext = function(config)
43614 Roo.apply(this, config);
43615 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43616 // dont call parent... till later.
43617 this.styles = this.styles || {};
43622 Roo.form.HtmlEditor.ToolbarContext.types = {
43634 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
43700 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
43705 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
43715 style : 'fontFamily',
43716 displayField: 'display',
43717 optname : 'font-family',
43766 // should we really allow this??
43767 // should this just be
43778 style : 'fontFamily',
43779 displayField: 'display',
43780 optname : 'font-family',
43787 style : 'fontFamily',
43788 displayField: 'display',
43789 optname : 'font-family',
43796 style : 'fontFamily',
43797 displayField: 'display',
43798 optname : 'font-family',
43809 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
43810 Roo.form.HtmlEditor.ToolbarContext.stores = false;
43812 Roo.form.HtmlEditor.ToolbarContext.options = {
43814 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
43815 [ 'Courier New', 'Courier New'],
43816 [ 'Tahoma', 'Tahoma'],
43817 [ 'Times New Roman,serif', 'Times'],
43818 [ 'Verdana','Verdana' ]
43822 // fixme - these need to be configurable..
43825 Roo.form.HtmlEditor.ToolbarContext.types
43828 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
43835 editorcore : false,
43837 * @cfg {Object} disable List of toolbar elements to disable
43842 * @cfg {Object} styles List of styles
43843 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
43845 * These must be defined in the page, so they get rendered correctly..
43856 init : function(editor)
43858 this.editor = editor;
43859 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43860 var editorcore = this.editorcore;
43862 var fid = editorcore.frameId;
43864 function btn(id, toggle, handler){
43865 var xid = fid + '-'+ id ;
43869 cls : 'x-btn-icon x-edit-'+id,
43870 enableToggle:toggle !== false,
43871 scope: editorcore, // was editor...
43872 handler:handler||editorcore.relayBtnCmd,
43873 clickEvent:'mousedown',
43874 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43878 // create a new element.
43879 var wdiv = editor.wrap.createChild({
43881 }, editor.wrap.dom.firstChild.nextSibling, true);
43883 // can we do this more than once??
43885 // stop form submits
43888 // disable everything...
43889 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43890 this.toolbars = {};
43892 for (var i in ty) {
43894 this.toolbars[i] = this.buildToolbar(ty[i],i);
43896 this.tb = this.toolbars.BODY;
43898 this.buildFooter();
43899 this.footer.show();
43900 editor.on('hide', function( ) { this.footer.hide() }, this);
43901 editor.on('show', function( ) { this.footer.show() }, this);
43904 this.rendered = true;
43906 // the all the btns;
43907 editor.on('editorevent', this.updateToolbar, this);
43908 // other toolbars need to implement this..
43909 //editor.on('editmodechange', this.updateToolbar, this);
43915 * Protected method that will not generally be called directly. It triggers
43916 * a toolbar update by reading the markup state of the current selection in the editor.
43918 updateToolbar: function(editor,ev,sel){
43921 // capture mouse up - this is handy for selecting images..
43922 // perhaps should go somewhere else...
43923 if(!this.editorcore.activated){
43924 this.editor.onFirstFocus();
43928 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
43929 // selectNode - might want to handle IE?
43931 (ev.type == 'mouseup' || ev.type == 'click' ) &&
43932 ev.target && ev.target.tagName == 'IMG') {
43933 // they have click on an image...
43934 // let's see if we can change the selection...
43937 var nodeRange = sel.ownerDocument.createRange();
43939 nodeRange.selectNode(sel);
43941 nodeRange.selectNodeContents(sel);
43943 //nodeRange.collapse(true);
43944 var s = this.editorcore.win.getSelection();
43945 s.removeAllRanges();
43946 s.addRange(nodeRange);
43950 var updateFooter = sel ? false : true;
43953 var ans = this.editorcore.getAllAncestors();
43956 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43959 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
43960 sel = sel ? sel : this.editorcore.doc.body;
43961 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
43964 // pick a menu that exists..
43965 var tn = sel.tagName.toUpperCase();
43966 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
43968 tn = sel.tagName.toUpperCase();
43970 var lastSel = this.tb.selectedNode
43972 this.tb.selectedNode = sel;
43974 // if current menu does not match..
43975 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
43978 ///console.log("show: " + tn);
43979 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
43982 this.tb.items.first().el.innerHTML = tn + ': ';
43985 // update attributes
43986 if (this.tb.fields) {
43987 this.tb.fields.each(function(e) {
43989 e.setValue(sel.style[e.stylename]);
43992 e.setValue(sel.getAttribute(e.attrname));
43996 var hasStyles = false;
43997 for(var i in this.styles) {
44004 var st = this.tb.fields.item(0);
44006 st.store.removeAll();
44009 var cn = sel.className.split(/\s+/);
44012 if (this.styles['*']) {
44014 Roo.each(this.styles['*'], function(v) {
44015 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44018 if (this.styles[tn]) {
44019 Roo.each(this.styles[tn], function(v) {
44020 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44024 st.store.loadData(avs);
44028 // flag our selected Node.
44029 this.tb.selectedNode = sel;
44032 Roo.menu.MenuMgr.hideAll();
44036 if (!updateFooter) {
44037 //this.footDisp.dom.innerHTML = '';
44040 // update the footer
44044 this.footerEls = ans.reverse();
44045 Roo.each(this.footerEls, function(a,i) {
44046 if (!a) { return; }
44047 html += html.length ? ' > ' : '';
44049 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44054 var sz = this.footDisp.up('td').getSize();
44055 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44056 this.footDisp.dom.style.marginLeft = '5px';
44058 this.footDisp.dom.style.overflow = 'hidden';
44060 this.footDisp.dom.innerHTML = html;
44062 //this.editorsyncValue();
44069 onDestroy : function(){
44072 this.tb.items.each(function(item){
44074 item.menu.removeAll();
44076 item.menu.el.destroy();
44084 onFirstFocus: function() {
44085 // need to do this for all the toolbars..
44086 this.tb.items.each(function(item){
44090 buildToolbar: function(tlist, nm)
44092 var editor = this.editor;
44093 var editorcore = this.editorcore;
44094 // create a new element.
44095 var wdiv = editor.wrap.createChild({
44097 }, editor.wrap.dom.firstChild.nextSibling, true);
44100 var tb = new Roo.Toolbar(wdiv);
44103 tb.add(nm+ ": ");
44106 for(var i in this.styles) {
44111 if (styles && styles.length) {
44113 // this needs a multi-select checkbox...
44114 tb.addField( new Roo.form.ComboBox({
44115 store: new Roo.data.SimpleStore({
44117 fields: ['val', 'selected'],
44120 name : '-roo-edit-className',
44121 attrname : 'className',
44122 displayField: 'val',
44126 triggerAction: 'all',
44127 emptyText:'Select Style',
44128 selectOnFocus:true,
44131 'select': function(c, r, i) {
44132 // initial support only for on class per el..
44133 tb.selectedNode.className = r ? r.get('val') : '';
44134 editorcore.syncValue();
44141 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44142 var tbops = tbc.options;
44144 for (var i in tlist) {
44146 var item = tlist[i];
44147 tb.add(item.title + ": ");
44150 //optname == used so you can configure the options available..
44151 var opts = item.opts ? item.opts : false;
44152 if (item.optname) {
44153 opts = tbops[item.optname];
44158 // opts == pulldown..
44159 tb.addField( new Roo.form.ComboBox({
44160 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44162 fields: ['val', 'display'],
44165 name : '-roo-edit-' + i,
44167 stylename : item.style ? item.style : false,
44168 displayField: item.displayField ? item.displayField : 'val',
44169 valueField : 'val',
44171 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44173 triggerAction: 'all',
44174 emptyText:'Select',
44175 selectOnFocus:true,
44176 width: item.width ? item.width : 130,
44178 'select': function(c, r, i) {
44180 tb.selectedNode.style[c.stylename] = r.get('val');
44183 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44192 tb.addField( new Roo.form.TextField({
44195 //allowBlank:false,
44200 tb.addField( new Roo.form.TextField({
44201 name: '-roo-edit-' + i,
44208 'change' : function(f, nv, ov) {
44209 tb.selectedNode.setAttribute(f.attrname, nv);
44218 text: 'Remove Tag',
44221 click : function ()
44224 // undo does not work.
44226 var sn = tb.selectedNode;
44228 var pn = sn.parentNode;
44230 var stn = sn.childNodes[0];
44231 var en = sn.childNodes[sn.childNodes.length - 1 ];
44232 while (sn.childNodes.length) {
44233 var node = sn.childNodes[0];
44234 sn.removeChild(node);
44236 pn.insertBefore(node, sn);
44239 pn.removeChild(sn);
44240 var range = editorcore.createRange();
44242 range.setStart(stn,0);
44243 range.setEnd(en,0); //????
44244 //range.selectNode(sel);
44247 var selection = editorcore.getSelection();
44248 selection.removeAllRanges();
44249 selection.addRange(range);
44253 //_this.updateToolbar(null, null, pn);
44254 _this.updateToolbar(null, null, null);
44255 _this.footDisp.dom.innerHTML = '';
44265 tb.el.on('click', function(e){
44266 e.preventDefault(); // what does this do?
44268 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44271 // dont need to disable them... as they will get hidden
44276 buildFooter : function()
44279 var fel = this.editor.wrap.createChild();
44280 this.footer = new Roo.Toolbar(fel);
44281 // toolbar has scrolly on left / right?
44282 var footDisp= new Roo.Toolbar.Fill();
44288 handler : function() {
44289 _t.footDisp.scrollTo('left',0,true)
44293 this.footer.add( footDisp );
44298 handler : function() {
44300 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44304 var fel = Roo.get(footDisp.el);
44305 fel.addClass('x-editor-context');
44306 this.footDispWrap = fel;
44307 this.footDispWrap.overflow = 'hidden';
44309 this.footDisp = fel.createChild();
44310 this.footDispWrap.on('click', this.onContextClick, this)
44314 onContextClick : function (ev,dom)
44316 ev.preventDefault();
44317 var cn = dom.className;
44319 if (!cn.match(/x-ed-loc-/)) {
44322 var n = cn.split('-').pop();
44323 var ans = this.footerEls;
44327 var range = this.editorcore.createRange();
44329 range.selectNodeContents(sel);
44330 //range.selectNode(sel);
44333 var selection = this.editorcore.getSelection();
44334 selection.removeAllRanges();
44335 selection.addRange(range);
44339 this.updateToolbar(null, null, sel);
44356 * Ext JS Library 1.1.1
44357 * Copyright(c) 2006-2007, Ext JS, LLC.
44359 * Originally Released Under LGPL - original licence link has changed is not relivant.
44362 * <script type="text/javascript">
44366 * @class Roo.form.BasicForm
44367 * @extends Roo.util.Observable
44368 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44370 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44371 * @param {Object} config Configuration options
44373 Roo.form.BasicForm = function(el, config){
44374 this.allItems = [];
44375 this.childForms = [];
44376 Roo.apply(this, config);
44378 * The Roo.form.Field items in this form.
44379 * @type MixedCollection
44383 this.items = new Roo.util.MixedCollection(false, function(o){
44384 return o.id || (o.id = Roo.id());
44388 * @event beforeaction
44389 * Fires before any action is performed. Return false to cancel the action.
44390 * @param {Form} this
44391 * @param {Action} action The action to be performed
44393 beforeaction: true,
44395 * @event actionfailed
44396 * Fires when an action fails.
44397 * @param {Form} this
44398 * @param {Action} action The action that failed
44400 actionfailed : true,
44402 * @event actioncomplete
44403 * Fires when an action is completed.
44404 * @param {Form} this
44405 * @param {Action} action The action that completed
44407 actioncomplete : true
44412 Roo.form.BasicForm.superclass.constructor.call(this);
44415 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44417 * @cfg {String} method
44418 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
44421 * @cfg {DataReader} reader
44422 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
44423 * This is optional as there is built-in support for processing JSON.
44426 * @cfg {DataReader} errorReader
44427 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
44428 * This is completely optional as there is built-in support for processing JSON.
44431 * @cfg {String} url
44432 * The URL to use for form actions if one isn't supplied in the action options.
44435 * @cfg {Boolean} fileUpload
44436 * Set to true if this form is a file upload.
44440 * @cfg {Object} baseParams
44441 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
44446 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
44451 activeAction : null,
44454 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
44455 * or setValues() data instead of when the form was first created.
44457 trackResetOnLoad : false,
44461 * childForms - used for multi-tab forms
44464 childForms : false,
44467 * allItems - full list of fields.
44473 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
44474 * element by passing it or its id or mask the form itself by passing in true.
44477 waitMsgTarget : false,
44480 initEl : function(el){
44481 this.el = Roo.get(el);
44482 this.id = this.el.id || Roo.id();
44483 this.el.on('submit', this.onSubmit, this);
44484 this.el.addClass('x-form');
44488 onSubmit : function(e){
44493 * Returns true if client-side validation on the form is successful.
44496 isValid : function(){
44498 this.items.each(function(f){
44507 * Returns true if any fields in this form have changed since their original load.
44510 isDirty : function(){
44512 this.items.each(function(f){
44522 * Performs a predefined action (submit or load) or custom actions you define on this form.
44523 * @param {String} actionName The name of the action type
44524 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
44525 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
44526 * accept other config options):
44528 Property Type Description
44529 ---------------- --------------- ----------------------------------------------------------------------------------
44530 url String The url for the action (defaults to the form's url)
44531 method String The form method to use (defaults to the form's method, or POST if not defined)
44532 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
44533 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
44534 validate the form on the client (defaults to false)
44536 * @return {BasicForm} this
44538 doAction : function(action, options){
44539 if(typeof action == 'string'){
44540 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
44542 if(this.fireEvent('beforeaction', this, action) !== false){
44543 this.beforeAction(action);
44544 action.run.defer(100, action);
44550 * Shortcut to do a submit action.
44551 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44552 * @return {BasicForm} this
44554 submit : function(options){
44555 this.doAction('submit', options);
44560 * Shortcut to do a load action.
44561 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44562 * @return {BasicForm} this
44564 load : function(options){
44565 this.doAction('load', options);
44570 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
44571 * @param {Record} record The record to edit
44572 * @return {BasicForm} this
44574 updateRecord : function(record){
44575 record.beginEdit();
44576 var fs = record.fields;
44577 fs.each(function(f){
44578 var field = this.findField(f.name);
44580 record.set(f.name, field.getValue());
44588 * Loads an Roo.data.Record into this form.
44589 * @param {Record} record The record to load
44590 * @return {BasicForm} this
44592 loadRecord : function(record){
44593 this.setValues(record.data);
44598 beforeAction : function(action){
44599 var o = action.options;
44602 if(this.waitMsgTarget === true){
44603 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
44604 }else if(this.waitMsgTarget){
44605 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
44606 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
44608 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
44614 afterAction : function(action, success){
44615 this.activeAction = null;
44616 var o = action.options;
44618 if(this.waitMsgTarget === true){
44620 }else if(this.waitMsgTarget){
44621 this.waitMsgTarget.unmask();
44623 Roo.MessageBox.updateProgress(1);
44624 Roo.MessageBox.hide();
44631 Roo.callback(o.success, o.scope, [this, action]);
44632 this.fireEvent('actioncomplete', this, action);
44636 // failure condition..
44637 // we have a scenario where updates need confirming.
44638 // eg. if a locking scenario exists..
44639 // we look for { errors : { needs_confirm : true }} in the response.
44641 (typeof(action.result) != 'undefined') &&
44642 (typeof(action.result.errors) != 'undefined') &&
44643 (typeof(action.result.errors.needs_confirm) != 'undefined')
44646 Roo.MessageBox.confirm(
44647 "Change requires confirmation",
44648 action.result.errorMsg,
44653 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
44663 Roo.callback(o.failure, o.scope, [this, action]);
44664 // show an error message if no failed handler is set..
44665 if (!this.hasListener('actionfailed')) {
44666 Roo.MessageBox.alert("Error",
44667 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
44668 action.result.errorMsg :
44669 "Saving Failed, please check your entries or try again"
44673 this.fireEvent('actionfailed', this, action);
44679 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
44680 * @param {String} id The value to search for
44683 findField : function(id){
44684 var field = this.items.get(id);
44686 this.items.each(function(f){
44687 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
44693 return field || null;
44697 * Add a secondary form to this one,
44698 * Used to provide tabbed forms. One form is primary, with hidden values
44699 * which mirror the elements from the other forms.
44701 * @param {Roo.form.Form} form to add.
44704 addForm : function(form)
44707 if (this.childForms.indexOf(form) > -1) {
44711 this.childForms.push(form);
44713 Roo.each(form.allItems, function (fe) {
44715 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
44716 if (this.findField(n)) { // already added..
44719 var add = new Roo.form.Hidden({
44722 add.render(this.el);
44729 * Mark fields in this form invalid in bulk.
44730 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
44731 * @return {BasicForm} this
44733 markInvalid : function(errors){
44734 if(errors instanceof Array){
44735 for(var i = 0, len = errors.length; i < len; i++){
44736 var fieldError = errors[i];
44737 var f = this.findField(fieldError.id);
44739 f.markInvalid(fieldError.msg);
44745 if(typeof errors[id] != 'function' && (field = this.findField(id))){
44746 field.markInvalid(errors[id]);
44750 Roo.each(this.childForms || [], function (f) {
44751 f.markInvalid(errors);
44758 * Set values for fields in this form in bulk.
44759 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
44760 * @return {BasicForm} this
44762 setValues : function(values){
44763 if(values instanceof Array){ // array of objects
44764 for(var i = 0, len = values.length; i < len; i++){
44766 var f = this.findField(v.id);
44768 f.setValue(v.value);
44769 if(this.trackResetOnLoad){
44770 f.originalValue = f.getValue();
44774 }else{ // object hash
44777 if(typeof values[id] != 'function' && (field = this.findField(id))){
44779 if (field.setFromData &&
44780 field.valueField &&
44781 field.displayField &&
44782 // combos' with local stores can
44783 // be queried via setValue()
44784 // to set their value..
44785 (field.store && !field.store.isLocal)
44789 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44790 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44791 field.setFromData(sd);
44794 field.setValue(values[id]);
44798 if(this.trackResetOnLoad){
44799 field.originalValue = field.getValue();
44805 Roo.each(this.childForms || [], function (f) {
44806 f.setValues(values);
44813 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
44814 * they are returned as an array.
44815 * @param {Boolean} asString
44818 getValues : function(asString){
44819 if (this.childForms) {
44820 // copy values from the child forms
44821 Roo.each(this.childForms, function (f) {
44822 this.setValues(f.getValues());
44828 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
44829 if(asString === true){
44832 return Roo.urlDecode(fs);
44836 * Returns the fields in this form as an object with key/value pairs.
44837 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
44840 getFieldValues : function(with_hidden)
44842 if (this.childForms) {
44843 // copy values from the child forms
44844 // should this call getFieldValues - probably not as we do not currently copy
44845 // hidden fields when we generate..
44846 Roo.each(this.childForms, function (f) {
44847 this.setValues(f.getValues());
44852 this.items.each(function(f){
44853 if (!f.getName()) {
44856 var v = f.getValue();
44857 if (f.inputType =='radio') {
44858 if (typeof(ret[f.getName()]) == 'undefined') {
44859 ret[f.getName()] = ''; // empty..
44862 if (!f.el.dom.checked) {
44866 v = f.el.dom.value;
44870 // not sure if this supported any more..
44871 if ((typeof(v) == 'object') && f.getRawValue) {
44872 v = f.getRawValue() ; // dates..
44874 // combo boxes where name != hiddenName...
44875 if (f.name != f.getName()) {
44876 ret[f.name] = f.getRawValue();
44878 ret[f.getName()] = v;
44885 * Clears all invalid messages in this form.
44886 * @return {BasicForm} this
44888 clearInvalid : function(){
44889 this.items.each(function(f){
44893 Roo.each(this.childForms || [], function (f) {
44902 * Resets this form.
44903 * @return {BasicForm} this
44905 reset : function(){
44906 this.items.each(function(f){
44910 Roo.each(this.childForms || [], function (f) {
44919 * Add Roo.form components to this form.
44920 * @param {Field} field1
44921 * @param {Field} field2 (optional)
44922 * @param {Field} etc (optional)
44923 * @return {BasicForm} this
44926 this.items.addAll(Array.prototype.slice.call(arguments, 0));
44932 * Removes a field from the items collection (does NOT remove its markup).
44933 * @param {Field} field
44934 * @return {BasicForm} this
44936 remove : function(field){
44937 this.items.remove(field);
44942 * Looks at the fields in this form, checks them for an id attribute,
44943 * and calls applyTo on the existing dom element with that id.
44944 * @return {BasicForm} this
44946 render : function(){
44947 this.items.each(function(f){
44948 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
44956 * Calls {@link Ext#apply} for all fields in this form with the passed object.
44957 * @param {Object} values
44958 * @return {BasicForm} this
44960 applyToFields : function(o){
44961 this.items.each(function(f){
44968 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
44969 * @param {Object} values
44970 * @return {BasicForm} this
44972 applyIfToFields : function(o){
44973 this.items.each(function(f){
44981 Roo.BasicForm = Roo.form.BasicForm;/*
44983 * Ext JS Library 1.1.1
44984 * Copyright(c) 2006-2007, Ext JS, LLC.
44986 * Originally Released Under LGPL - original licence link has changed is not relivant.
44989 * <script type="text/javascript">
44993 * @class Roo.form.Form
44994 * @extends Roo.form.BasicForm
44995 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
44997 * @param {Object} config Configuration options
44999 Roo.form.Form = function(config){
45001 if (config.items) {
45002 xitems = config.items;
45003 delete config.items;
45007 Roo.form.Form.superclass.constructor.call(this, null, config);
45008 this.url = this.url || this.action;
45010 this.root = new Roo.form.Layout(Roo.applyIf({
45014 this.active = this.root;
45016 * Array of all the buttons that have been added to this form via {@link addButton}
45020 this.allItems = [];
45023 * @event clientvalidation
45024 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45025 * @param {Form} this
45026 * @param {Boolean} valid true if the form has passed client-side validation
45028 clientvalidation: true,
45031 * Fires when the form is rendered
45032 * @param {Roo.form.Form} form
45037 if (this.progressUrl) {
45038 // push a hidden field onto the list of fields..
45042 name : 'UPLOAD_IDENTIFIER'
45047 Roo.each(xitems, this.addxtype, this);
45053 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45055 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45058 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45061 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45063 buttonAlign:'center',
45066 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45071 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45072 * This property cascades to child containers if not set.
45077 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45078 * fires a looping event with that state. This is required to bind buttons to the valid
45079 * state using the config value formBind:true on the button.
45081 monitorValid : false,
45084 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45089 * @cfg {String} progressUrl - Url to return progress data
45092 progressUrl : false,
45095 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45096 * fields are added and the column is closed. If no fields are passed the column remains open
45097 * until end() is called.
45098 * @param {Object} config The config to pass to the column
45099 * @param {Field} field1 (optional)
45100 * @param {Field} field2 (optional)
45101 * @param {Field} etc (optional)
45102 * @return Column The column container object
45104 column : function(c){
45105 var col = new Roo.form.Column(c);
45107 if(arguments.length > 1){ // duplicate code required because of Opera
45108 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45115 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45116 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45117 * until end() is called.
45118 * @param {Object} config The config to pass to the fieldset
45119 * @param {Field} field1 (optional)
45120 * @param {Field} field2 (optional)
45121 * @param {Field} etc (optional)
45122 * @return FieldSet The fieldset container object
45124 fieldset : function(c){
45125 var fs = new Roo.form.FieldSet(c);
45127 if(arguments.length > 1){ // duplicate code required because of Opera
45128 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45135 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45136 * fields are added and the container is closed. If no fields are passed the container remains open
45137 * until end() is called.
45138 * @param {Object} config The config to pass to the Layout
45139 * @param {Field} field1 (optional)
45140 * @param {Field} field2 (optional)
45141 * @param {Field} etc (optional)
45142 * @return Layout The container object
45144 container : function(c){
45145 var l = new Roo.form.Layout(c);
45147 if(arguments.length > 1){ // duplicate code required because of Opera
45148 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45155 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45156 * @param {Object} container A Roo.form.Layout or subclass of Layout
45157 * @return {Form} this
45159 start : function(c){
45160 // cascade label info
45161 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45162 this.active.stack.push(c);
45163 c.ownerCt = this.active;
45169 * Closes the current open container
45170 * @return {Form} this
45173 if(this.active == this.root){
45176 this.active = this.active.ownerCt;
45181 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45182 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45183 * as the label of the field.
45184 * @param {Field} field1
45185 * @param {Field} field2 (optional)
45186 * @param {Field} etc. (optional)
45187 * @return {Form} this
45190 this.active.stack.push.apply(this.active.stack, arguments);
45191 this.allItems.push.apply(this.allItems,arguments);
45193 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45194 if(a[i].isFormField){
45199 Roo.form.Form.superclass.add.apply(this, r);
45209 * Find any element that has been added to a form, using it's ID or name
45210 * This can include framesets, columns etc. along with regular fields..
45211 * @param {String} id - id or name to find.
45213 * @return {Element} e - or false if nothing found.
45215 findbyId : function(id)
45221 Roo.each(this.allItems, function(f){
45222 if (f.id == id || f.name == id ){
45233 * Render this form into the passed container. This should only be called once!
45234 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45235 * @return {Form} this
45237 render : function(ct)
45243 var o = this.autoCreate || {
45245 method : this.method || 'POST',
45246 id : this.id || Roo.id()
45248 this.initEl(ct.createChild(o));
45250 this.root.render(this.el);
45254 this.items.each(function(f){
45255 f.render('x-form-el-'+f.id);
45258 if(this.buttons.length > 0){
45259 // tables are required to maintain order and for correct IE layout
45260 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45261 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45262 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45264 var tr = tb.getElementsByTagName('tr')[0];
45265 for(var i = 0, len = this.buttons.length; i < len; i++) {
45266 var b = this.buttons[i];
45267 var td = document.createElement('td');
45268 td.className = 'x-form-btn-td';
45269 b.render(tr.appendChild(td));
45272 if(this.monitorValid){ // initialize after render
45273 this.startMonitoring();
45275 this.fireEvent('rendered', this);
45280 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45281 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45282 * object or a valid Roo.DomHelper element config
45283 * @param {Function} handler The function called when the button is clicked
45284 * @param {Object} scope (optional) The scope of the handler function
45285 * @return {Roo.Button}
45287 addButton : function(config, handler, scope){
45291 minWidth: this.minButtonWidth,
45294 if(typeof config == "string"){
45297 Roo.apply(bc, config);
45299 var btn = new Roo.Button(null, bc);
45300 this.buttons.push(btn);
45305 * Adds a series of form elements (using the xtype property as the factory method.
45306 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45307 * @param {Object} config
45310 addxtype : function()
45312 var ar = Array.prototype.slice.call(arguments, 0);
45314 for(var i = 0; i < ar.length; i++) {
45316 continue; // skip -- if this happends something invalid got sent, we
45317 // should ignore it, as basically that interface element will not show up
45318 // and that should be pretty obvious!!
45321 if (Roo.form[ar[i].xtype]) {
45323 var fe = Roo.factory(ar[i], Roo.form);
45329 fe.store.form = this;
45334 this.allItems.push(fe);
45335 if (fe.items && fe.addxtype) {
45336 fe.addxtype.apply(fe, fe.items);
45346 // console.log('adding ' + ar[i].xtype);
45348 if (ar[i].xtype == 'Button') {
45349 //console.log('adding button');
45350 //console.log(ar[i]);
45351 this.addButton(ar[i]);
45352 this.allItems.push(fe);
45356 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45357 alert('end is not supported on xtype any more, use items');
45359 // //console.log('adding end');
45367 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45368 * option "monitorValid"
45370 startMonitoring : function(){
45373 Roo.TaskMgr.start({
45374 run : this.bindHandler,
45375 interval : this.monitorPoll || 200,
45382 * Stops monitoring of the valid state of this form
45384 stopMonitoring : function(){
45385 this.bound = false;
45389 bindHandler : function(){
45391 return false; // stops binding
45394 this.items.each(function(f){
45395 if(!f.isValid(true)){
45400 for(var i = 0, len = this.buttons.length; i < len; i++){
45401 var btn = this.buttons[i];
45402 if(btn.formBind === true && btn.disabled === valid){
45403 btn.setDisabled(!valid);
45406 this.fireEvent('clientvalidation', this, valid);
45420 Roo.Form = Roo.form.Form;
45423 * Ext JS Library 1.1.1
45424 * Copyright(c) 2006-2007, Ext JS, LLC.
45426 * Originally Released Under LGPL - original licence link has changed is not relivant.
45429 * <script type="text/javascript">
45432 // as we use this in bootstrap.
45433 Roo.namespace('Roo.form');
45435 * @class Roo.form.Action
45436 * Internal Class used to handle form actions
45438 * @param {Roo.form.BasicForm} el The form element or its id
45439 * @param {Object} config Configuration options
45444 // define the action interface
45445 Roo.form.Action = function(form, options){
45447 this.options = options || {};
45450 * Client Validation Failed
45453 Roo.form.Action.CLIENT_INVALID = 'client';
45455 * Server Validation Failed
45458 Roo.form.Action.SERVER_INVALID = 'server';
45460 * Connect to Server Failed
45463 Roo.form.Action.CONNECT_FAILURE = 'connect';
45465 * Reading Data from Server Failed
45468 Roo.form.Action.LOAD_FAILURE = 'load';
45470 Roo.form.Action.prototype = {
45472 failureType : undefined,
45473 response : undefined,
45474 result : undefined,
45476 // interface method
45477 run : function(options){
45481 // interface method
45482 success : function(response){
45486 // interface method
45487 handleResponse : function(response){
45491 // default connection failure
45492 failure : function(response){
45494 this.response = response;
45495 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45496 this.form.afterAction(this, false);
45499 processResponse : function(response){
45500 this.response = response;
45501 if(!response.responseText){
45504 this.result = this.handleResponse(response);
45505 return this.result;
45508 // utility functions used internally
45509 getUrl : function(appendParams){
45510 var url = this.options.url || this.form.url || this.form.el.dom.action;
45512 var p = this.getParams();
45514 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
45520 getMethod : function(){
45521 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
45524 getParams : function(){
45525 var bp = this.form.baseParams;
45526 var p = this.options.params;
45528 if(typeof p == "object"){
45529 p = Roo.urlEncode(Roo.applyIf(p, bp));
45530 }else if(typeof p == 'string' && bp){
45531 p += '&' + Roo.urlEncode(bp);
45534 p = Roo.urlEncode(bp);
45539 createCallback : function(){
45541 success: this.success,
45542 failure: this.failure,
45544 timeout: (this.form.timeout*1000),
45545 upload: this.form.fileUpload ? this.success : undefined
45550 Roo.form.Action.Submit = function(form, options){
45551 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
45554 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
45557 haveProgress : false,
45558 uploadComplete : false,
45560 // uploadProgress indicator.
45561 uploadProgress : function()
45563 if (!this.form.progressUrl) {
45567 if (!this.haveProgress) {
45568 Roo.MessageBox.progress("Uploading", "Uploading");
45570 if (this.uploadComplete) {
45571 Roo.MessageBox.hide();
45575 this.haveProgress = true;
45577 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
45579 var c = new Roo.data.Connection();
45581 url : this.form.progressUrl,
45586 success : function(req){
45587 //console.log(data);
45591 rdata = Roo.decode(req.responseText)
45593 Roo.log("Invalid data from server..");
45597 if (!rdata || !rdata.success) {
45599 Roo.MessageBox.alert(Roo.encode(rdata));
45602 var data = rdata.data;
45604 if (this.uploadComplete) {
45605 Roo.MessageBox.hide();
45610 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
45611 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
45614 this.uploadProgress.defer(2000,this);
45617 failure: function(data) {
45618 Roo.log('progress url failed ');
45629 // run get Values on the form, so it syncs any secondary forms.
45630 this.form.getValues();
45632 var o = this.options;
45633 var method = this.getMethod();
45634 var isPost = method == 'POST';
45635 if(o.clientValidation === false || this.form.isValid()){
45637 if (this.form.progressUrl) {
45638 this.form.findField('UPLOAD_IDENTIFIER').setValue(
45639 (new Date() * 1) + '' + Math.random());
45644 Roo.Ajax.request(Roo.apply(this.createCallback(), {
45645 form:this.form.el.dom,
45646 url:this.getUrl(!isPost),
45648 params:isPost ? this.getParams() : null,
45649 isUpload: this.form.fileUpload
45652 this.uploadProgress();
45654 }else if (o.clientValidation !== false){ // client validation failed
45655 this.failureType = Roo.form.Action.CLIENT_INVALID;
45656 this.form.afterAction(this, false);
45660 success : function(response)
45662 this.uploadComplete= true;
45663 if (this.haveProgress) {
45664 Roo.MessageBox.hide();
45668 var result = this.processResponse(response);
45669 if(result === true || result.success){
45670 this.form.afterAction(this, true);
45674 this.form.markInvalid(result.errors);
45675 this.failureType = Roo.form.Action.SERVER_INVALID;
45677 this.form.afterAction(this, false);
45679 failure : function(response)
45681 this.uploadComplete= true;
45682 if (this.haveProgress) {
45683 Roo.MessageBox.hide();
45686 this.response = response;
45687 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45688 this.form.afterAction(this, false);
45691 handleResponse : function(response){
45692 if(this.form.errorReader){
45693 var rs = this.form.errorReader.read(response);
45696 for(var i = 0, len = rs.records.length; i < len; i++) {
45697 var r = rs.records[i];
45698 errors[i] = r.data;
45701 if(errors.length < 1){
45705 success : rs.success,
45711 ret = Roo.decode(response.responseText);
45715 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
45725 Roo.form.Action.Load = function(form, options){
45726 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
45727 this.reader = this.form.reader;
45730 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
45735 Roo.Ajax.request(Roo.apply(
45736 this.createCallback(), {
45737 method:this.getMethod(),
45738 url:this.getUrl(false),
45739 params:this.getParams()
45743 success : function(response){
45745 var result = this.processResponse(response);
45746 if(result === true || !result.success || !result.data){
45747 this.failureType = Roo.form.Action.LOAD_FAILURE;
45748 this.form.afterAction(this, false);
45751 this.form.clearInvalid();
45752 this.form.setValues(result.data);
45753 this.form.afterAction(this, true);
45756 handleResponse : function(response){
45757 if(this.form.reader){
45758 var rs = this.form.reader.read(response);
45759 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
45761 success : rs.success,
45765 return Roo.decode(response.responseText);
45769 Roo.form.Action.ACTION_TYPES = {
45770 'load' : Roo.form.Action.Load,
45771 'submit' : Roo.form.Action.Submit
45774 * Ext JS Library 1.1.1
45775 * Copyright(c) 2006-2007, Ext JS, LLC.
45777 * Originally Released Under LGPL - original licence link has changed is not relivant.
45780 * <script type="text/javascript">
45784 * @class Roo.form.Layout
45785 * @extends Roo.Component
45786 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45788 * @param {Object} config Configuration options
45790 Roo.form.Layout = function(config){
45792 if (config.items) {
45793 xitems = config.items;
45794 delete config.items;
45796 Roo.form.Layout.superclass.constructor.call(this, config);
45798 Roo.each(xitems, this.addxtype, this);
45802 Roo.extend(Roo.form.Layout, Roo.Component, {
45804 * @cfg {String/Object} autoCreate
45805 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
45808 * @cfg {String/Object/Function} style
45809 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
45810 * a function which returns such a specification.
45813 * @cfg {String} labelAlign
45814 * Valid values are "left," "top" and "right" (defaults to "left")
45817 * @cfg {Number} labelWidth
45818 * Fixed width in pixels of all field labels (defaults to undefined)
45821 * @cfg {Boolean} clear
45822 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
45826 * @cfg {String} labelSeparator
45827 * The separator to use after field labels (defaults to ':')
45829 labelSeparator : ':',
45831 * @cfg {Boolean} hideLabels
45832 * True to suppress the display of field labels in this layout (defaults to false)
45834 hideLabels : false,
45837 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
45842 onRender : function(ct, position){
45843 if(this.el){ // from markup
45844 this.el = Roo.get(this.el);
45845 }else { // generate
45846 var cfg = this.getAutoCreate();
45847 this.el = ct.createChild(cfg, position);
45850 this.el.applyStyles(this.style);
45852 if(this.labelAlign){
45853 this.el.addClass('x-form-label-'+this.labelAlign);
45855 if(this.hideLabels){
45856 this.labelStyle = "display:none";
45857 this.elementStyle = "padding-left:0;";
45859 if(typeof this.labelWidth == 'number'){
45860 this.labelStyle = "width:"+this.labelWidth+"px;";
45861 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
45863 if(this.labelAlign == 'top'){
45864 this.labelStyle = "width:auto;";
45865 this.elementStyle = "padding-left:0;";
45868 var stack = this.stack;
45869 var slen = stack.length;
45871 if(!this.fieldTpl){
45872 var t = new Roo.Template(
45873 '<div class="x-form-item {5}">',
45874 '<label for="{0}" style="{2}">{1}{4}</label>',
45875 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45877 '</div><div class="x-form-clear-left"></div>'
45879 t.disableFormats = true;
45881 Roo.form.Layout.prototype.fieldTpl = t;
45883 for(var i = 0; i < slen; i++) {
45884 if(stack[i].isFormField){
45885 this.renderField(stack[i]);
45887 this.renderComponent(stack[i]);
45892 this.el.createChild({cls:'x-form-clear'});
45897 renderField : function(f){
45898 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
45901 f.labelStyle||this.labelStyle||'', //2
45902 this.elementStyle||'', //3
45903 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
45904 f.itemCls||this.itemCls||'' //5
45905 ], true).getPrevSibling());
45909 renderComponent : function(c){
45910 c.render(c.isLayout ? this.el : this.el.createChild());
45913 * Adds a object form elements (using the xtype property as the factory method.)
45914 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
45915 * @param {Object} config
45917 addxtype : function(o)
45919 // create the lement.
45920 o.form = this.form;
45921 var fe = Roo.factory(o, Roo.form);
45922 this.form.allItems.push(fe);
45923 this.stack.push(fe);
45925 if (fe.isFormField) {
45926 this.form.items.add(fe);
45934 * @class Roo.form.Column
45935 * @extends Roo.form.Layout
45936 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
45938 * @param {Object} config Configuration options
45940 Roo.form.Column = function(config){
45941 Roo.form.Column.superclass.constructor.call(this, config);
45944 Roo.extend(Roo.form.Column, Roo.form.Layout, {
45946 * @cfg {Number/String} width
45947 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45950 * @cfg {String/Object} autoCreate
45951 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
45955 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
45958 onRender : function(ct, position){
45959 Roo.form.Column.superclass.onRender.call(this, ct, position);
45961 this.el.setWidth(this.width);
45968 * @class Roo.form.Row
45969 * @extends Roo.form.Layout
45970 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
45972 * @param {Object} config Configuration options
45976 Roo.form.Row = function(config){
45977 Roo.form.Row.superclass.constructor.call(this, config);
45980 Roo.extend(Roo.form.Row, Roo.form.Layout, {
45982 * @cfg {Number/String} width
45983 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45986 * @cfg {Number/String} height
45987 * The fixed height of the column in pixels or CSS value (defaults to "auto")
45989 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
45993 onRender : function(ct, position){
45994 //console.log('row render');
45996 var t = new Roo.Template(
45997 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
45998 '<label for="{0}" style="{2}">{1}{4}</label>',
45999 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46003 t.disableFormats = true;
46005 Roo.form.Layout.prototype.rowTpl = t;
46007 this.fieldTpl = this.rowTpl;
46009 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46010 var labelWidth = 100;
46012 if ((this.labelAlign != 'top')) {
46013 if (typeof this.labelWidth == 'number') {
46014 labelWidth = this.labelWidth
46016 this.padWidth = 20 + labelWidth;
46020 Roo.form.Column.superclass.onRender.call(this, ct, position);
46022 this.el.setWidth(this.width);
46025 this.el.setHeight(this.height);
46030 renderField : function(f){
46031 f.fieldEl = this.fieldTpl.append(this.el, [
46032 f.id, f.fieldLabel,
46033 f.labelStyle||this.labelStyle||'',
46034 this.elementStyle||'',
46035 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46036 f.itemCls||this.itemCls||'',
46037 f.width ? f.width + this.padWidth : 160 + this.padWidth
46044 * @class Roo.form.FieldSet
46045 * @extends Roo.form.Layout
46046 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46048 * @param {Object} config Configuration options
46050 Roo.form.FieldSet = function(config){
46051 Roo.form.FieldSet.superclass.constructor.call(this, config);
46054 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46056 * @cfg {String} legend
46057 * The text to display as the legend for the FieldSet (defaults to '')
46060 * @cfg {String/Object} autoCreate
46061 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46065 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46068 onRender : function(ct, position){
46069 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46071 this.setLegend(this.legend);
46076 setLegend : function(text){
46078 this.el.child('legend').update(text);
46083 * Ext JS Library 1.1.1
46084 * Copyright(c) 2006-2007, Ext JS, LLC.
46086 * Originally Released Under LGPL - original licence link has changed is not relivant.
46089 * <script type="text/javascript">
46092 * @class Roo.form.VTypes
46093 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46096 Roo.form.VTypes = function(){
46097 // closure these in so they are only created once.
46098 var alpha = /^[a-zA-Z_]+$/;
46099 var alphanum = /^[a-zA-Z0-9_]+$/;
46100 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46101 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46103 // All these messages and functions are configurable
46106 * The function used to validate email addresses
46107 * @param {String} value The email address
46109 'email' : function(v){
46110 return email.test(v);
46113 * The error text to display when the email validation function returns false
46116 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46118 * The keystroke filter mask to be applied on email input
46121 'emailMask' : /[a-z0-9_\.\-@]/i,
46124 * The function used to validate URLs
46125 * @param {String} value The URL
46127 'url' : function(v){
46128 return url.test(v);
46131 * The error text to display when the url validation function returns false
46134 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46137 * The function used to validate alpha values
46138 * @param {String} value The value
46140 'alpha' : function(v){
46141 return alpha.test(v);
46144 * The error text to display when the alpha validation function returns false
46147 'alphaText' : 'This field should only contain letters and _',
46149 * The keystroke filter mask to be applied on alpha input
46152 'alphaMask' : /[a-z_]/i,
46155 * The function used to validate alphanumeric values
46156 * @param {String} value The value
46158 'alphanum' : function(v){
46159 return alphanum.test(v);
46162 * The error text to display when the alphanumeric validation function returns false
46165 'alphanumText' : 'This field should only contain letters, numbers and _',
46167 * The keystroke filter mask to be applied on alphanumeric input
46170 'alphanumMask' : /[a-z0-9_]/i
46172 }();//<script type="text/javascript">
46175 * @class Roo.form.FCKeditor
46176 * @extends Roo.form.TextArea
46177 * Wrapper around the FCKEditor http://www.fckeditor.net
46179 * Creates a new FCKeditor
46180 * @param {Object} config Configuration options
46182 Roo.form.FCKeditor = function(config){
46183 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46186 * @event editorinit
46187 * Fired when the editor is initialized - you can add extra handlers here..
46188 * @param {FCKeditor} this
46189 * @param {Object} the FCK object.
46196 Roo.form.FCKeditor.editors = { };
46197 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46199 //defaultAutoCreate : {
46200 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46204 * @cfg {Object} fck options - see fck manual for details.
46209 * @cfg {Object} fck toolbar set (Basic or Default)
46211 toolbarSet : 'Basic',
46213 * @cfg {Object} fck BasePath
46215 basePath : '/fckeditor/',
46223 onRender : function(ct, position)
46226 this.defaultAutoCreate = {
46228 style:"width:300px;height:60px;",
46229 autocomplete: "off"
46232 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46235 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46236 if(this.preventScrollbars){
46237 this.el.setStyle("overflow", "hidden");
46239 this.el.setHeight(this.growMin);
46242 //console.log('onrender' + this.getId() );
46243 Roo.form.FCKeditor.editors[this.getId()] = this;
46246 this.replaceTextarea() ;
46250 getEditor : function() {
46251 return this.fckEditor;
46254 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46255 * @param {Mixed} value The value to set
46259 setValue : function(value)
46261 //console.log('setValue: ' + value);
46263 if(typeof(value) == 'undefined') { // not sure why this is happending...
46266 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46268 //if(!this.el || !this.getEditor()) {
46269 // this.value = value;
46270 //this.setValue.defer(100,this,[value]);
46274 if(!this.getEditor()) {
46278 this.getEditor().SetData(value);
46285 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46286 * @return {Mixed} value The field value
46288 getValue : function()
46291 if (this.frame && this.frame.dom.style.display == 'none') {
46292 return Roo.form.FCKeditor.superclass.getValue.call(this);
46295 if(!this.el || !this.getEditor()) {
46297 // this.getValue.defer(100,this);
46302 var value=this.getEditor().GetData();
46303 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46304 return Roo.form.FCKeditor.superclass.getValue.call(this);
46310 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46311 * @return {Mixed} value The field value
46313 getRawValue : function()
46315 if (this.frame && this.frame.dom.style.display == 'none') {
46316 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46319 if(!this.el || !this.getEditor()) {
46320 //this.getRawValue.defer(100,this);
46327 var value=this.getEditor().GetData();
46328 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46329 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46333 setSize : function(w,h) {
46337 //if (this.frame && this.frame.dom.style.display == 'none') {
46338 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46341 //if(!this.el || !this.getEditor()) {
46342 // this.setSize.defer(100,this, [w,h]);
46348 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46350 this.frame.dom.setAttribute('width', w);
46351 this.frame.dom.setAttribute('height', h);
46352 this.frame.setSize(w,h);
46356 toggleSourceEdit : function(value) {
46360 this.el.dom.style.display = value ? '' : 'none';
46361 this.frame.dom.style.display = value ? 'none' : '';
46366 focus: function(tag)
46368 if (this.frame.dom.style.display == 'none') {
46369 return Roo.form.FCKeditor.superclass.focus.call(this);
46371 if(!this.el || !this.getEditor()) {
46372 this.focus.defer(100,this, [tag]);
46379 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46380 this.getEditor().Focus();
46382 if (!this.getEditor().Selection.GetSelection()) {
46383 this.focus.defer(100,this, [tag]);
46388 var r = this.getEditor().EditorDocument.createRange();
46389 r.setStart(tgs[0],0);
46390 r.setEnd(tgs[0],0);
46391 this.getEditor().Selection.GetSelection().removeAllRanges();
46392 this.getEditor().Selection.GetSelection().addRange(r);
46393 this.getEditor().Focus();
46400 replaceTextarea : function()
46402 if ( document.getElementById( this.getId() + '___Frame' ) )
46404 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46406 // We must check the elements firstly using the Id and then the name.
46407 var oTextarea = document.getElementById( this.getId() );
46409 var colElementsByName = document.getElementsByName( this.getId() ) ;
46411 oTextarea.style.display = 'none' ;
46413 if ( oTextarea.tabIndex ) {
46414 this.TabIndex = oTextarea.tabIndex ;
46417 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46418 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46419 this.frame = Roo.get(this.getId() + '___Frame')
46422 _getConfigHtml : function()
46426 for ( var o in this.fckconfig ) {
46427 sConfig += sConfig.length > 0 ? '&' : '';
46428 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
46431 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
46435 _getIFrameHtml : function()
46437 var sFile = 'fckeditor.html' ;
46438 /* no idea what this is about..
46441 if ( (/fcksource=true/i).test( window.top.location.search ) )
46442 sFile = 'fckeditor.original.html' ;
46447 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
46448 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
46451 var html = '<iframe id="' + this.getId() +
46452 '___Frame" src="' + sLink +
46453 '" width="' + this.width +
46454 '" height="' + this.height + '"' +
46455 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
46456 ' frameborder="0" scrolling="no"></iframe>' ;
46461 _insertHtmlBefore : function( html, element )
46463 if ( element.insertAdjacentHTML ) {
46465 element.insertAdjacentHTML( 'beforeBegin', html ) ;
46467 var oRange = document.createRange() ;
46468 oRange.setStartBefore( element ) ;
46469 var oFragment = oRange.createContextualFragment( html );
46470 element.parentNode.insertBefore( oFragment, element ) ;
46483 //Roo.reg('fckeditor', Roo.form.FCKeditor);
46485 function FCKeditor_OnComplete(editorInstance){
46486 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
46487 f.fckEditor = editorInstance;
46488 //console.log("loaded");
46489 f.fireEvent('editorinit', f, editorInstance);
46509 //<script type="text/javascript">
46511 * @class Roo.form.GridField
46512 * @extends Roo.form.Field
46513 * Embed a grid (or editable grid into a form)
46516 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
46518 * xgrid.store = Roo.data.Store
46519 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
46520 * xgrid.store.reader = Roo.data.JsonReader
46524 * Creates a new GridField
46525 * @param {Object} config Configuration options
46527 Roo.form.GridField = function(config){
46528 Roo.form.GridField.superclass.constructor.call(this, config);
46532 Roo.extend(Roo.form.GridField, Roo.form.Field, {
46534 * @cfg {Number} width - used to restrict width of grid..
46538 * @cfg {Number} height - used to restrict height of grid..
46542 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
46548 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46549 * {tag: "input", type: "checkbox", autocomplete: "off"})
46551 // defaultAutoCreate : { tag: 'div' },
46552 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46554 * @cfg {String} addTitle Text to include for adding a title.
46558 onResize : function(){
46559 Roo.form.Field.superclass.onResize.apply(this, arguments);
46562 initEvents : function(){
46563 // Roo.form.Checkbox.superclass.initEvents.call(this);
46564 // has no events...
46569 getResizeEl : function(){
46573 getPositionEl : function(){
46578 onRender : function(ct, position){
46580 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
46581 var style = this.style;
46584 Roo.form.GridField.superclass.onRender.call(this, ct, position);
46585 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
46586 this.viewEl = this.wrap.createChild({ tag: 'div' });
46588 this.viewEl.applyStyles(style);
46591 this.viewEl.setWidth(this.width);
46594 this.viewEl.setHeight(this.height);
46596 //if(this.inputValue !== undefined){
46597 //this.setValue(this.value);
46600 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
46603 this.grid.render();
46604 this.grid.getDataSource().on('remove', this.refreshValue, this);
46605 this.grid.getDataSource().on('update', this.refreshValue, this);
46606 this.grid.on('afteredit', this.refreshValue, this);
46612 * Sets the value of the item.
46613 * @param {String} either an object or a string..
46615 setValue : function(v){
46617 v = v || []; // empty set..
46618 // this does not seem smart - it really only affects memoryproxy grids..
46619 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
46620 var ds = this.grid.getDataSource();
46621 // assumes a json reader..
46623 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
46624 ds.loadData( data);
46626 // clear selection so it does not get stale.
46627 if (this.grid.sm) {
46628 this.grid.sm.clearSelections();
46631 Roo.form.GridField.superclass.setValue.call(this, v);
46632 this.refreshValue();
46633 // should load data in the grid really....
46637 refreshValue: function() {
46639 this.grid.getDataSource().each(function(r) {
46642 this.el.dom.value = Roo.encode(val);
46650 * Ext JS Library 1.1.1
46651 * Copyright(c) 2006-2007, Ext JS, LLC.
46653 * Originally Released Under LGPL - original licence link has changed is not relivant.
46656 * <script type="text/javascript">
46659 * @class Roo.form.DisplayField
46660 * @extends Roo.form.Field
46661 * A generic Field to display non-editable data.
46663 * Creates a new Display Field item.
46664 * @param {Object} config Configuration options
46666 Roo.form.DisplayField = function(config){
46667 Roo.form.DisplayField.superclass.constructor.call(this, config);
46671 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
46672 inputType: 'hidden',
46678 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46680 focusClass : undefined,
46682 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46684 fieldClass: 'x-form-field',
46687 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
46689 valueRenderer: undefined,
46693 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46694 * {tag: "input", type: "checkbox", autocomplete: "off"})
46697 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46699 onResize : function(){
46700 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
46704 initEvents : function(){
46705 // Roo.form.Checkbox.superclass.initEvents.call(this);
46706 // has no events...
46711 getResizeEl : function(){
46715 getPositionEl : function(){
46720 onRender : function(ct, position){
46722 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
46723 //if(this.inputValue !== undefined){
46724 this.wrap = this.el.wrap();
46726 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
46728 if (this.bodyStyle) {
46729 this.viewEl.applyStyles(this.bodyStyle);
46731 //this.viewEl.setStyle('padding', '2px');
46733 this.setValue(this.value);
46738 initValue : Roo.emptyFn,
46743 onClick : function(){
46748 * Sets the checked state of the checkbox.
46749 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
46751 setValue : function(v){
46753 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
46754 // this might be called before we have a dom element..
46755 if (!this.viewEl) {
46758 this.viewEl.dom.innerHTML = html;
46759 Roo.form.DisplayField.superclass.setValue.call(this, v);
46769 * @class Roo.form.DayPicker
46770 * @extends Roo.form.Field
46771 * A Day picker show [M] [T] [W] ....
46773 * Creates a new Day Picker
46774 * @param {Object} config Configuration options
46776 Roo.form.DayPicker= function(config){
46777 Roo.form.DayPicker.superclass.constructor.call(this, config);
46781 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
46783 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46785 focusClass : undefined,
46787 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46789 fieldClass: "x-form-field",
46792 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46793 * {tag: "input", type: "checkbox", autocomplete: "off"})
46795 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
46798 actionMode : 'viewEl',
46802 inputType : 'hidden',
46805 inputElement: false, // real input element?
46806 basedOn: false, // ????
46808 isFormField: true, // not sure where this is needed!!!!
46810 onResize : function(){
46811 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
46812 if(!this.boxLabel){
46813 this.el.alignTo(this.wrap, 'c-c');
46817 initEvents : function(){
46818 Roo.form.Checkbox.superclass.initEvents.call(this);
46819 this.el.on("click", this.onClick, this);
46820 this.el.on("change", this.onClick, this);
46824 getResizeEl : function(){
46828 getPositionEl : function(){
46834 onRender : function(ct, position){
46835 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
46837 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
46839 var r1 = '<table><tr>';
46840 var r2 = '<tr class="x-form-daypick-icons">';
46841 for (var i=0; i < 7; i++) {
46842 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
46843 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
46846 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
46847 viewEl.select('img').on('click', this.onClick, this);
46848 this.viewEl = viewEl;
46851 // this will not work on Chrome!!!
46852 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
46853 this.el.on('propertychange', this.setFromHidden, this); //ie
46861 initValue : Roo.emptyFn,
46864 * Returns the checked state of the checkbox.
46865 * @return {Boolean} True if checked, else false
46867 getValue : function(){
46868 return this.el.dom.value;
46873 onClick : function(e){
46874 //this.setChecked(!this.checked);
46875 Roo.get(e.target).toggleClass('x-menu-item-checked');
46876 this.refreshValue();
46877 //if(this.el.dom.checked != this.checked){
46878 // this.setValue(this.el.dom.checked);
46883 refreshValue : function()
46886 this.viewEl.select('img',true).each(function(e,i,n) {
46887 val += e.is(".x-menu-item-checked") ? String(n) : '';
46889 this.setValue(val, true);
46893 * Sets the checked state of the checkbox.
46894 * On is always based on a string comparison between inputValue and the param.
46895 * @param {Boolean/String} value - the value to set
46896 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
46898 setValue : function(v,suppressEvent){
46899 if (!this.el.dom) {
46902 var old = this.el.dom.value ;
46903 this.el.dom.value = v;
46904 if (suppressEvent) {
46908 // update display..
46909 this.viewEl.select('img',true).each(function(e,i,n) {
46911 var on = e.is(".x-menu-item-checked");
46912 var newv = v.indexOf(String(n)) > -1;
46914 e.toggleClass('x-menu-item-checked');
46920 this.fireEvent('change', this, v, old);
46925 // handle setting of hidden value by some other method!!?!?
46926 setFromHidden: function()
46931 //console.log("SET FROM HIDDEN");
46932 //alert('setFrom hidden');
46933 this.setValue(this.el.dom.value);
46936 onDestroy : function()
46939 Roo.get(this.viewEl).remove();
46942 Roo.form.DayPicker.superclass.onDestroy.call(this);
46946 * RooJS Library 1.1.1
46947 * Copyright(c) 2008-2011 Alan Knowles
46954 * @class Roo.form.ComboCheck
46955 * @extends Roo.form.ComboBox
46956 * A combobox for multiple select items.
46958 * FIXME - could do with a reset button..
46961 * Create a new ComboCheck
46962 * @param {Object} config Configuration options
46964 Roo.form.ComboCheck = function(config){
46965 Roo.form.ComboCheck.superclass.constructor.call(this, config);
46966 // should verify some data...
46968 // hiddenName = required..
46969 // displayField = required
46970 // valudField == required
46971 var req= [ 'hiddenName', 'displayField', 'valueField' ];
46973 Roo.each(req, function(e) {
46974 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
46975 throw "Roo.form.ComboCheck : missing value for: " + e;
46982 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
46987 selectedClass: 'x-menu-item-checked',
46990 onRender : function(ct, position){
46996 var cls = 'x-combo-list';
46999 this.tpl = new Roo.Template({
47000 html : '<div class="'+cls+'-item x-menu-check-item">' +
47001 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47002 '<span>{' + this.displayField + '}</span>' +
47009 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47010 this.view.singleSelect = false;
47011 this.view.multiSelect = true;
47012 this.view.toggleSelect = true;
47013 this.pageTb.add(new Roo.Toolbar.Fill(), {
47016 handler: function()
47023 onViewOver : function(e, t){
47029 onViewClick : function(doFocus,index){
47033 select: function () {
47034 //Roo.log("SELECT CALLED");
47037 selectByValue : function(xv, scrollIntoView){
47038 var ar = this.getValueArray();
47041 Roo.each(ar, function(v) {
47042 if(v === undefined || v === null){
47045 var r = this.findRecord(this.valueField, v);
47047 sels.push(this.store.indexOf(r))
47051 this.view.select(sels);
47057 onSelect : function(record, index){
47058 // Roo.log("onselect Called");
47059 // this is only called by the clear button now..
47060 this.view.clearSelections();
47061 this.setValue('[]');
47062 if (this.value != this.valueBefore) {
47063 this.fireEvent('change', this, this.value, this.valueBefore);
47064 this.valueBefore = this.value;
47067 getValueArray : function()
47072 //Roo.log(this.value);
47073 if (typeof(this.value) == 'undefined') {
47076 var ar = Roo.decode(this.value);
47077 return ar instanceof Array ? ar : []; //?? valid?
47080 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47085 expand : function ()
47088 Roo.form.ComboCheck.superclass.expand.call(this);
47089 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47090 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47095 collapse : function(){
47096 Roo.form.ComboCheck.superclass.collapse.call(this);
47097 var sl = this.view.getSelectedIndexes();
47098 var st = this.store;
47102 Roo.each(sl, function(i) {
47104 nv.push(r.get(this.valueField));
47106 this.setValue(Roo.encode(nv));
47107 if (this.value != this.valueBefore) {
47109 this.fireEvent('change', this, this.value, this.valueBefore);
47110 this.valueBefore = this.value;
47115 setValue : function(v){
47119 var vals = this.getValueArray();
47121 Roo.each(vals, function(k) {
47122 var r = this.findRecord(this.valueField, k);
47124 tv.push(r.data[this.displayField]);
47125 }else if(this.valueNotFoundText !== undefined){
47126 tv.push( this.valueNotFoundText );
47131 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47132 this.hiddenField.value = v;
47138 * Ext JS Library 1.1.1
47139 * Copyright(c) 2006-2007, Ext JS, LLC.
47141 * Originally Released Under LGPL - original licence link has changed is not relivant.
47144 * <script type="text/javascript">
47148 * @class Roo.form.Signature
47149 * @extends Roo.form.Field
47153 * @param {Object} config Configuration options
47156 Roo.form.Signature = function(config){
47157 Roo.form.Signature.superclass.constructor.call(this, config);
47159 this.addEvents({// not in used??
47162 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47163 * @param {Roo.form.Signature} combo This combo box
47168 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47169 * @param {Roo.form.ComboBox} combo This combo box
47170 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47176 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47178 * @cfg {Object} labels Label to use when rendering a form.
47182 * confirm : "Confirm"
47187 confirm : "Confirm"
47190 * @cfg {Number} width The signature panel width (defaults to 300)
47194 * @cfg {Number} height The signature panel height (defaults to 100)
47198 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47200 allowBlank : false,
47203 // {Object} signPanel The signature SVG panel element (defaults to {})
47205 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47206 isMouseDown : false,
47207 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47208 isConfirmed : false,
47209 // {String} signatureTmp SVG mapping string (defaults to empty string)
47213 defaultAutoCreate : { // modified by initCompnoent..
47219 onRender : function(ct, position){
47221 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47223 this.wrap = this.el.wrap({
47224 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47227 this.createToolbar(this);
47228 this.signPanel = this.wrap.createChild({
47230 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47234 this.svgID = Roo.id();
47235 this.svgEl = this.signPanel.createChild({
47236 xmlns : 'http://www.w3.org/2000/svg',
47238 id : this.svgID + "-svg",
47240 height: this.height,
47241 viewBox: '0 0 '+this.width+' '+this.height,
47245 id: this.svgID + "-svg-r",
47247 height: this.height,
47252 id: this.svgID + "-svg-l",
47254 y1: (this.height*0.8), // start set the line in 80% of height
47255 x2: this.width, // end
47256 y2: (this.height*0.8), // end set the line in 80% of height
47258 'stroke-width': "1",
47259 'stroke-dasharray': "3",
47260 'shape-rendering': "crispEdges",
47261 'pointer-events': "none"
47265 id: this.svgID + "-svg-p",
47267 'stroke-width': "3",
47269 'pointer-events': 'none'
47274 this.svgBox = this.svgEl.dom.getScreenCTM();
47276 createSVG : function(){
47277 var svg = this.signPanel;
47278 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47281 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47282 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47283 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47284 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47285 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47286 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47287 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47290 isTouchEvent : function(e){
47291 return e.type.match(/^touch/);
47293 getCoords : function (e) {
47294 var pt = this.svgEl.dom.createSVGPoint();
47297 if (this.isTouchEvent(e)) {
47298 pt.x = e.targetTouches[0].clientX
47299 pt.y = e.targetTouches[0].clientY;
47301 var a = this.svgEl.dom.getScreenCTM();
47302 var b = a.inverse();
47303 var mx = pt.matrixTransform(b);
47304 return mx.x + ',' + mx.y;
47306 //mouse event headler
47307 down : function (e) {
47308 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47309 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47311 this.isMouseDown = true;
47313 e.preventDefault();
47315 move : function (e) {
47316 if (this.isMouseDown) {
47317 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47318 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47321 e.preventDefault();
47323 up : function (e) {
47324 this.isMouseDown = false;
47325 var sp = this.signatureTmp.split(' ');
47328 if(!sp[sp.length-2].match(/^L/)){
47332 this.signatureTmp = sp.join(" ");
47335 if(this.getValue() != this.signatureTmp){
47336 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47337 this.isConfirmed = false;
47339 e.preventDefault();
47343 * Protected method that will not generally be called directly. It
47344 * is called when the editor creates its toolbar. Override this method if you need to
47345 * add custom toolbar buttons.
47346 * @param {HtmlEditor} editor
47348 createToolbar : function(editor){
47349 function btn(id, toggle, handler){
47350 var xid = fid + '-'+ id ;
47354 cls : 'x-btn-icon x-edit-'+id,
47355 enableToggle:toggle !== false,
47356 scope: editor, // was editor...
47357 handler:handler||editor.relayBtnCmd,
47358 clickEvent:'mousedown',
47359 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47365 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47369 cls : ' x-signature-btn x-signature-'+id,
47370 scope: editor, // was editor...
47371 handler: this.reset,
47372 clickEvent:'mousedown',
47373 text: this.labels.clear
47380 cls : ' x-signature-btn x-signature-'+id,
47381 scope: editor, // was editor...
47382 handler: this.confirmHandler,
47383 clickEvent:'mousedown',
47384 text: this.labels.confirm
47391 * when user is clicked confirm then show this image.....
47393 * @return {String} Image Data URI
47395 getImageDataURI : function(){
47396 var svg = this.svgEl.dom.parentNode.innerHTML;
47397 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47402 * @return {Boolean} this.isConfirmed
47404 getConfirmed : function(){
47405 return this.isConfirmed;
47409 * @return {Number} this.width
47411 getWidth : function(){
47416 * @return {Number} this.height
47418 getHeight : function(){
47419 return this.height;
47422 getSignature : function(){
47423 return this.signatureTmp;
47426 reset : function(){
47427 this.signatureTmp = '';
47428 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47429 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
47430 this.isConfirmed = false;
47431 Roo.form.Signature.superclass.reset.call(this);
47433 setSignature : function(s){
47434 this.signatureTmp = s;
47435 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47436 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
47438 this.isConfirmed = false;
47439 Roo.form.Signature.superclass.reset.call(this);
47442 // Roo.log(this.signPanel.dom.contentWindow.up())
47445 setConfirmed : function(){
47449 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
47452 confirmHandler : function(){
47453 if(!this.getSignature()){
47457 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
47458 this.setValue(this.getSignature());
47459 this.isConfirmed = true;
47461 this.fireEvent('confirm', this);
47464 // Subclasses should provide the validation implementation by overriding this
47465 validateValue : function(value){
47466 if(this.allowBlank){
47470 if(this.isConfirmed){
47477 * Ext JS Library 1.1.1
47478 * Copyright(c) 2006-2007, Ext JS, LLC.
47480 * Originally Released Under LGPL - original licence link has changed is not relivant.
47483 * <script type="text/javascript">
47488 * @class Roo.form.ComboBox
47489 * @extends Roo.form.TriggerField
47490 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
47492 * Create a new ComboBox.
47493 * @param {Object} config Configuration options
47495 Roo.form.Select = function(config){
47496 Roo.form.Select.superclass.constructor.call(this, config);
47500 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
47502 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
47505 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
47506 * rendering into an Roo.Editor, defaults to false)
47509 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
47510 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
47513 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
47516 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
47517 * the dropdown list (defaults to undefined, with no header element)
47521 * @cfg {String/Roo.Template} tpl The template to use to render the output
47525 defaultAutoCreate : {tag: "select" },
47527 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
47529 listWidth: undefined,
47531 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
47532 * mode = 'remote' or 'text' if mode = 'local')
47534 displayField: undefined,
47536 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
47537 * mode = 'remote' or 'value' if mode = 'local').
47538 * Note: use of a valueField requires the user make a selection
47539 * in order for a value to be mapped.
47541 valueField: undefined,
47545 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
47546 * field's data value (defaults to the underlying DOM element's name)
47548 hiddenName: undefined,
47550 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
47554 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
47556 selectedClass: 'x-combo-selected',
47558 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
47559 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
47560 * which displays a downward arrow icon).
47562 triggerClass : 'x-form-arrow-trigger',
47564 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
47568 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
47569 * anchor positions (defaults to 'tl-bl')
47571 listAlign: 'tl-bl?',
47573 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
47577 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
47578 * query specified by the allQuery config option (defaults to 'query')
47580 triggerAction: 'query',
47582 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
47583 * (defaults to 4, does not apply if editable = false)
47587 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
47588 * delay (typeAheadDelay) if it matches a known value (defaults to false)
47592 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
47593 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
47597 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
47598 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
47602 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
47603 * when editable = true (defaults to false)
47605 selectOnFocus:false,
47607 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
47609 queryParam: 'query',
47611 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
47612 * when mode = 'remote' (defaults to 'Loading...')
47614 loadingText: 'Loading...',
47616 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
47620 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
47624 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
47625 * traditional select (defaults to true)
47629 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
47633 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
47637 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
47638 * listWidth has a higher value)
47642 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
47643 * allow the user to set arbitrary text into the field (defaults to false)
47645 forceSelection:false,
47647 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
47648 * if typeAhead = true (defaults to 250)
47650 typeAheadDelay : 250,
47652 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
47653 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
47655 valueNotFoundText : undefined,
47658 * @cfg {String} defaultValue The value displayed after loading the store.
47663 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
47665 blockFocus : false,
47668 * @cfg {Boolean} disableClear Disable showing of clear button.
47670 disableClear : false,
47672 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
47674 alwaysQuery : false,
47680 // element that contains real text value.. (when hidden is used..)
47683 onRender : function(ct, position){
47684 Roo.form.Field.prototype.onRender.call(this, ct, position);
47687 this.store.on('beforeload', this.onBeforeLoad, this);
47688 this.store.on('load', this.onLoad, this);
47689 this.store.on('loadexception', this.onLoadException, this);
47690 this.store.load({});
47698 initEvents : function(){
47699 //Roo.form.ComboBox.superclass.initEvents.call(this);
47703 onDestroy : function(){
47706 this.store.un('beforeload', this.onBeforeLoad, this);
47707 this.store.un('load', this.onLoad, this);
47708 this.store.un('loadexception', this.onLoadException, this);
47710 //Roo.form.ComboBox.superclass.onDestroy.call(this);
47714 fireKey : function(e){
47715 if(e.isNavKeyPress() && !this.list.isVisible()){
47716 this.fireEvent("specialkey", this, e);
47721 onResize: function(w, h){
47729 * Allow or prevent the user from directly editing the field text. If false is passed,
47730 * the user will only be able to select from the items defined in the dropdown list. This method
47731 * is the runtime equivalent of setting the 'editable' config option at config time.
47732 * @param {Boolean} value True to allow the user to directly edit the field text
47734 setEditable : function(value){
47739 onBeforeLoad : function(){
47741 Roo.log("Select before load");
47744 this.innerList.update(this.loadingText ?
47745 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
47746 //this.restrictHeight();
47747 this.selectedIndex = -1;
47751 onLoad : function(){
47754 var dom = this.el.dom;
47755 dom.innerHTML = '';
47756 var od = dom.ownerDocument;
47758 if (this.emptyText) {
47759 var op = od.createElement('option');
47760 op.setAttribute('value', '');
47761 op.innerHTML = String.format('{0}', this.emptyText);
47762 dom.appendChild(op);
47764 if(this.store.getCount() > 0){
47766 var vf = this.valueField;
47767 var df = this.displayField;
47768 this.store.data.each(function(r) {
47769 // which colmsn to use... testing - cdoe / title..
47770 var op = od.createElement('option');
47771 op.setAttribute('value', r.data[vf]);
47772 op.innerHTML = String.format('{0}', r.data[df]);
47773 dom.appendChild(op);
47775 if (typeof(this.defaultValue != 'undefined')) {
47776 this.setValue(this.defaultValue);
47781 //this.onEmptyResults();
47786 onLoadException : function()
47788 dom.innerHTML = '';
47790 Roo.log("Select on load exception");
47794 Roo.log(this.store.reader.jsonData);
47795 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
47796 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
47802 onTypeAhead : function(){
47807 onSelect : function(record, index){
47808 Roo.log('on select?');
47810 if(this.fireEvent('beforeselect', this, record, index) !== false){
47811 this.setFromData(index > -1 ? record.data : false);
47813 this.fireEvent('select', this, record, index);
47818 * Returns the currently selected field value or empty string if no value is set.
47819 * @return {String} value The selected value
47821 getValue : function(){
47822 var dom = this.el.dom;
47823 this.value = dom.options[dom.selectedIndex].value;
47829 * Clears any text/value currently set in the field
47831 clearValue : function(){
47833 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
47838 * Sets the specified value into the field. If the value finds a match, the corresponding record text
47839 * will be displayed in the field. If the value does not match the data value of an existing item,
47840 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
47841 * Otherwise the field will be blank (although the value will still be set).
47842 * @param {String} value The value to match
47844 setValue : function(v){
47845 var d = this.el.dom;
47846 for (var i =0; i < d.options.length;i++) {
47847 if (v == d.options[i].value) {
47848 d.selectedIndex = i;
47856 * @property {Object} the last set data for the element
47861 * Sets the value of the field based on a object which is related to the record format for the store.
47862 * @param {Object} value the value to set as. or false on reset?
47864 setFromData : function(o){
47865 Roo.log('setfrom data?');
47871 reset : function(){
47875 findRecord : function(prop, value){
47880 if(this.store.getCount() > 0){
47881 this.store.each(function(r){
47882 if(r.data[prop] == value){
47892 getName: function()
47894 // returns hidden if it's set..
47895 if (!this.rendered) {return ''};
47896 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
47904 onEmptyResults : function(){
47905 Roo.log('empty results');
47910 * Returns true if the dropdown list is expanded, else false.
47912 isExpanded : function(){
47917 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
47918 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47919 * @param {String} value The data value of the item to select
47920 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47921 * selected item if it is not currently in view (defaults to true)
47922 * @return {Boolean} True if the value matched an item in the list, else false
47924 selectByValue : function(v, scrollIntoView){
47925 Roo.log('select By Value');
47928 if(v !== undefined && v !== null){
47929 var r = this.findRecord(this.valueField || this.displayField, v);
47931 this.select(this.store.indexOf(r), scrollIntoView);
47939 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
47940 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47941 * @param {Number} index The zero-based index of the list item to select
47942 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47943 * selected item if it is not currently in view (defaults to true)
47945 select : function(index, scrollIntoView){
47946 Roo.log('select ');
47949 this.selectedIndex = index;
47950 this.view.select(index);
47951 if(scrollIntoView !== false){
47952 var el = this.view.getNode(index);
47954 this.innerList.scrollChildIntoView(el, false);
47962 validateBlur : function(){
47969 initQuery : function(){
47970 this.doQuery(this.getRawValue());
47974 doForce : function(){
47975 if(this.el.dom.value.length > 0){
47976 this.el.dom.value =
47977 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
47983 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
47984 * query allowing the query action to be canceled if needed.
47985 * @param {String} query The SQL query to execute
47986 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
47987 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
47988 * saved in the current store (defaults to false)
47990 doQuery : function(q, forceAll){
47992 Roo.log('doQuery?');
47993 if(q === undefined || q === null){
47998 forceAll: forceAll,
48002 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48006 forceAll = qe.forceAll;
48007 if(forceAll === true || (q.length >= this.minChars)){
48008 if(this.lastQuery != q || this.alwaysQuery){
48009 this.lastQuery = q;
48010 if(this.mode == 'local'){
48011 this.selectedIndex = -1;
48013 this.store.clearFilter();
48015 this.store.filter(this.displayField, q);
48019 this.store.baseParams[this.queryParam] = q;
48021 params: this.getParams(q)
48026 this.selectedIndex = -1;
48033 getParams : function(q){
48035 //p[this.queryParam] = q;
48038 p.limit = this.pageSize;
48044 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48046 collapse : function(){
48051 collapseIf : function(e){
48056 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48058 expand : function(){
48066 * @cfg {Boolean} grow
48070 * @cfg {Number} growMin
48074 * @cfg {Number} growMax
48082 setWidth : function()
48086 getResizeEl : function(){
48089 });//<script type="text/javasscript">
48093 * @class Roo.DDView
48094 * A DnD enabled version of Roo.View.
48095 * @param {Element/String} container The Element in which to create the View.
48096 * @param {String} tpl The template string used to create the markup for each element of the View
48097 * @param {Object} config The configuration properties. These include all the config options of
48098 * {@link Roo.View} plus some specific to this class.<br>
48100 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48101 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48103 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48104 .x-view-drag-insert-above {
48105 border-top:1px dotted #3366cc;
48107 .x-view-drag-insert-below {
48108 border-bottom:1px dotted #3366cc;
48114 Roo.DDView = function(container, tpl, config) {
48115 Roo.DDView.superclass.constructor.apply(this, arguments);
48116 this.getEl().setStyle("outline", "0px none");
48117 this.getEl().unselectable();
48118 if (this.dragGroup) {
48119 this.setDraggable(this.dragGroup.split(","));
48121 if (this.dropGroup) {
48122 this.setDroppable(this.dropGroup.split(","));
48124 if (this.deletable) {
48125 this.setDeletable();
48127 this.isDirtyFlag = false;
48133 Roo.extend(Roo.DDView, Roo.View, {
48134 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48135 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48136 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48137 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48141 reset: Roo.emptyFn,
48143 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48145 validate: function() {
48149 destroy: function() {
48150 this.purgeListeners();
48151 this.getEl.removeAllListeners();
48152 this.getEl().remove();
48153 if (this.dragZone) {
48154 if (this.dragZone.destroy) {
48155 this.dragZone.destroy();
48158 if (this.dropZone) {
48159 if (this.dropZone.destroy) {
48160 this.dropZone.destroy();
48165 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48166 getName: function() {
48170 /** Loads the View from a JSON string representing the Records to put into the Store. */
48171 setValue: function(v) {
48173 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48176 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48177 this.store.proxy = new Roo.data.MemoryProxy(data);
48181 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48182 getValue: function() {
48184 this.store.each(function(rec) {
48185 result += rec.id + ',';
48187 return result.substr(0, result.length - 1) + ')';
48190 getIds: function() {
48191 var i = 0, result = new Array(this.store.getCount());
48192 this.store.each(function(rec) {
48193 result[i++] = rec.id;
48198 isDirty: function() {
48199 return this.isDirtyFlag;
48203 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48204 * whole Element becomes the target, and this causes the drop gesture to append.
48206 getTargetFromEvent : function(e) {
48207 var target = e.getTarget();
48208 while ((target !== null) && (target.parentNode != this.el.dom)) {
48209 target = target.parentNode;
48212 target = this.el.dom.lastChild || this.el.dom;
48218 * Create the drag data which consists of an object which has the property "ddel" as
48219 * the drag proxy element.
48221 getDragData : function(e) {
48222 var target = this.findItemFromChild(e.getTarget());
48224 this.handleSelection(e);
48225 var selNodes = this.getSelectedNodes();
48228 copy: this.copy || (this.allowCopy && e.ctrlKey),
48232 var selectedIndices = this.getSelectedIndexes();
48233 for (var i = 0; i < selectedIndices.length; i++) {
48234 dragData.records.push(this.store.getAt(selectedIndices[i]));
48236 if (selNodes.length == 1) {
48237 dragData.ddel = target.cloneNode(true); // the div element
48239 var div = document.createElement('div'); // create the multi element drag "ghost"
48240 div.className = 'multi-proxy';
48241 for (var i = 0, len = selNodes.length; i < len; i++) {
48242 div.appendChild(selNodes[i].cloneNode(true));
48244 dragData.ddel = div;
48246 //console.log(dragData)
48247 //console.log(dragData.ddel.innerHTML)
48250 //console.log('nodragData')
48254 /** Specify to which ddGroup items in this DDView may be dragged. */
48255 setDraggable: function(ddGroup) {
48256 if (ddGroup instanceof Array) {
48257 Roo.each(ddGroup, this.setDraggable, this);
48260 if (this.dragZone) {
48261 this.dragZone.addToGroup(ddGroup);
48263 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48264 containerScroll: true,
48268 // Draggability implies selection. DragZone's mousedown selects the element.
48269 if (!this.multiSelect) { this.singleSelect = true; }
48271 // Wire the DragZone's handlers up to methods in *this*
48272 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48276 /** Specify from which ddGroup this DDView accepts drops. */
48277 setDroppable: function(ddGroup) {
48278 if (ddGroup instanceof Array) {
48279 Roo.each(ddGroup, this.setDroppable, this);
48282 if (this.dropZone) {
48283 this.dropZone.addToGroup(ddGroup);
48285 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48286 containerScroll: true,
48290 // Wire the DropZone's handlers up to methods in *this*
48291 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48292 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48293 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48294 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48295 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48299 /** Decide whether to drop above or below a View node. */
48300 getDropPoint : function(e, n, dd){
48301 if (n == this.el.dom) { return "above"; }
48302 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48303 var c = t + (b - t) / 2;
48304 var y = Roo.lib.Event.getPageY(e);
48312 onNodeEnter : function(n, dd, e, data){
48316 onNodeOver : function(n, dd, e, data){
48317 var pt = this.getDropPoint(e, n, dd);
48318 // set the insert point style on the target node
48319 var dragElClass = this.dropNotAllowed;
48322 if (pt == "above"){
48323 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48324 targetElClass = "x-view-drag-insert-above";
48326 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48327 targetElClass = "x-view-drag-insert-below";
48329 if (this.lastInsertClass != targetElClass){
48330 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48331 this.lastInsertClass = targetElClass;
48334 return dragElClass;
48337 onNodeOut : function(n, dd, e, data){
48338 this.removeDropIndicators(n);
48341 onNodeDrop : function(n, dd, e, data){
48342 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48345 var pt = this.getDropPoint(e, n, dd);
48346 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48347 if (pt == "below") { insertAt++; }
48348 for (var i = 0; i < data.records.length; i++) {
48349 var r = data.records[i];
48350 var dup = this.store.getById(r.id);
48351 if (dup && (dd != this.dragZone)) {
48352 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48355 this.store.insert(insertAt++, r.copy());
48357 data.source.isDirtyFlag = true;
48359 this.store.insert(insertAt++, r);
48361 this.isDirtyFlag = true;
48364 this.dragZone.cachedTarget = null;
48368 removeDropIndicators : function(n){
48370 Roo.fly(n).removeClass([
48371 "x-view-drag-insert-above",
48372 "x-view-drag-insert-below"]);
48373 this.lastInsertClass = "_noclass";
48378 * Utility method. Add a delete option to the DDView's context menu.
48379 * @param {String} imageUrl The URL of the "delete" icon image.
48381 setDeletable: function(imageUrl) {
48382 if (!this.singleSelect && !this.multiSelect) {
48383 this.singleSelect = true;
48385 var c = this.getContextMenu();
48386 this.contextMenu.on("itemclick", function(item) {
48389 this.remove(this.getSelectedIndexes());
48393 this.contextMenu.add({
48400 /** Return the context menu for this DDView. */
48401 getContextMenu: function() {
48402 if (!this.contextMenu) {
48403 // Create the View's context menu
48404 this.contextMenu = new Roo.menu.Menu({
48405 id: this.id + "-contextmenu"
48407 this.el.on("contextmenu", this.showContextMenu, this);
48409 return this.contextMenu;
48412 disableContextMenu: function() {
48413 if (this.contextMenu) {
48414 this.el.un("contextmenu", this.showContextMenu, this);
48418 showContextMenu: function(e, item) {
48419 item = this.findItemFromChild(e.getTarget());
48422 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
48423 this.contextMenu.showAt(e.getXY());
48428 * Remove {@link Roo.data.Record}s at the specified indices.
48429 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
48431 remove: function(selectedIndices) {
48432 selectedIndices = [].concat(selectedIndices);
48433 for (var i = 0; i < selectedIndices.length; i++) {
48434 var rec = this.store.getAt(selectedIndices[i]);
48435 this.store.remove(rec);
48440 * Double click fires the event, but also, if this is draggable, and there is only one other
48441 * related DropZone, it transfers the selected node.
48443 onDblClick : function(e){
48444 var item = this.findItemFromChild(e.getTarget());
48446 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
48449 if (this.dragGroup) {
48450 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
48451 while (targets.indexOf(this.dropZone) > -1) {
48452 targets.remove(this.dropZone);
48454 if (targets.length == 1) {
48455 this.dragZone.cachedTarget = null;
48456 var el = Roo.get(targets[0].getEl());
48457 var box = el.getBox(true);
48458 targets[0].onNodeDrop(el.dom, {
48460 xy: [box.x, box.y + box.height - 1]
48461 }, null, this.getDragData(e));
48467 handleSelection: function(e) {
48468 this.dragZone.cachedTarget = null;
48469 var item = this.findItemFromChild(e.getTarget());
48471 this.clearSelections(true);
48474 if (item && (this.multiSelect || this.singleSelect)){
48475 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
48476 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
48477 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
48478 this.unselect(item);
48480 this.select(item, this.multiSelect && e.ctrlKey);
48481 this.lastSelection = item;
48486 onItemClick : function(item, index, e){
48487 if(this.fireEvent("beforeclick", this, index, item, e) === false){
48493 unselect : function(nodeInfo, suppressEvent){
48494 var node = this.getNode(nodeInfo);
48495 if(node && this.isSelected(node)){
48496 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
48497 Roo.fly(node).removeClass(this.selectedClass);
48498 this.selections.remove(node);
48499 if(!suppressEvent){
48500 this.fireEvent("selectionchange", this, this.selections);
48508 * Ext JS Library 1.1.1
48509 * Copyright(c) 2006-2007, Ext JS, LLC.
48511 * Originally Released Under LGPL - original licence link has changed is not relivant.
48514 * <script type="text/javascript">
48518 * @class Roo.LayoutManager
48519 * @extends Roo.util.Observable
48520 * Base class for layout managers.
48522 Roo.LayoutManager = function(container, config){
48523 Roo.LayoutManager.superclass.constructor.call(this);
48524 this.el = Roo.get(container);
48525 // ie scrollbar fix
48526 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
48527 document.body.scroll = "no";
48528 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
48529 this.el.position('relative');
48531 this.id = this.el.id;
48532 this.el.addClass("x-layout-container");
48533 /** false to disable window resize monitoring @type Boolean */
48534 this.monitorWindowResize = true;
48539 * Fires when a layout is performed.
48540 * @param {Roo.LayoutManager} this
48544 * @event regionresized
48545 * Fires when the user resizes a region.
48546 * @param {Roo.LayoutRegion} region The resized region
48547 * @param {Number} newSize The new size (width for east/west, height for north/south)
48549 "regionresized" : true,
48551 * @event regioncollapsed
48552 * Fires when a region is collapsed.
48553 * @param {Roo.LayoutRegion} region The collapsed region
48555 "regioncollapsed" : true,
48557 * @event regionexpanded
48558 * Fires when a region is expanded.
48559 * @param {Roo.LayoutRegion} region The expanded region
48561 "regionexpanded" : true
48563 this.updating = false;
48564 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48567 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
48569 * Returns true if this layout is currently being updated
48570 * @return {Boolean}
48572 isUpdating : function(){
48573 return this.updating;
48577 * Suspend the LayoutManager from doing auto-layouts while
48578 * making multiple add or remove calls
48580 beginUpdate : function(){
48581 this.updating = true;
48585 * Restore auto-layouts and optionally disable the manager from performing a layout
48586 * @param {Boolean} noLayout true to disable a layout update
48588 endUpdate : function(noLayout){
48589 this.updating = false;
48595 layout: function(){
48599 onRegionResized : function(region, newSize){
48600 this.fireEvent("regionresized", region, newSize);
48604 onRegionCollapsed : function(region){
48605 this.fireEvent("regioncollapsed", region);
48608 onRegionExpanded : function(region){
48609 this.fireEvent("regionexpanded", region);
48613 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
48614 * performs box-model adjustments.
48615 * @return {Object} The size as an object {width: (the width), height: (the height)}
48617 getViewSize : function(){
48619 if(this.el.dom != document.body){
48620 size = this.el.getSize();
48622 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
48624 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
48625 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
48630 * Returns the Element this layout is bound to.
48631 * @return {Roo.Element}
48633 getEl : function(){
48638 * Returns the specified region.
48639 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
48640 * @return {Roo.LayoutRegion}
48642 getRegion : function(target){
48643 return this.regions[target.toLowerCase()];
48646 onWindowResize : function(){
48647 if(this.monitorWindowResize){
48653 * Ext JS Library 1.1.1
48654 * Copyright(c) 2006-2007, Ext JS, LLC.
48656 * Originally Released Under LGPL - original licence link has changed is not relivant.
48659 * <script type="text/javascript">
48662 * @class Roo.BorderLayout
48663 * @extends Roo.LayoutManager
48664 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
48665 * please see: <br><br>
48666 * <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>
48667 * <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>
48670 var layout = new Roo.BorderLayout(document.body, {
48704 preferredTabWidth: 150
48709 var CP = Roo.ContentPanel;
48711 layout.beginUpdate();
48712 layout.add("north", new CP("north", "North"));
48713 layout.add("south", new CP("south", {title: "South", closable: true}));
48714 layout.add("west", new CP("west", {title: "West"}));
48715 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
48716 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
48717 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
48718 layout.getRegion("center").showPanel("center1");
48719 layout.endUpdate();
48722 <b>The container the layout is rendered into can be either the body element or any other element.
48723 If it is not the body element, the container needs to either be an absolute positioned element,
48724 or you will need to add "position:relative" to the css of the container. You will also need to specify
48725 the container size if it is not the body element.</b>
48728 * Create a new BorderLayout
48729 * @param {String/HTMLElement/Element} container The container this layout is bound to
48730 * @param {Object} config Configuration options
48732 Roo.BorderLayout = function(container, config){
48733 config = config || {};
48734 Roo.BorderLayout.superclass.constructor.call(this, container, config);
48735 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
48736 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
48737 var target = this.factory.validRegions[i];
48738 if(config[target]){
48739 this.addRegion(target, config[target]);
48744 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
48746 * Creates and adds a new region if it doesn't already exist.
48747 * @param {String} target The target region key (north, south, east, west or center).
48748 * @param {Object} config The regions config object
48749 * @return {BorderLayoutRegion} The new region
48751 addRegion : function(target, config){
48752 if(!this.regions[target]){
48753 var r = this.factory.create(target, this, config);
48754 this.bindRegion(target, r);
48756 return this.regions[target];
48760 bindRegion : function(name, r){
48761 this.regions[name] = r;
48762 r.on("visibilitychange", this.layout, this);
48763 r.on("paneladded", this.layout, this);
48764 r.on("panelremoved", this.layout, this);
48765 r.on("invalidated", this.layout, this);
48766 r.on("resized", this.onRegionResized, this);
48767 r.on("collapsed", this.onRegionCollapsed, this);
48768 r.on("expanded", this.onRegionExpanded, this);
48772 * Performs a layout update.
48774 layout : function(){
48775 if(this.updating) return;
48776 var size = this.getViewSize();
48777 var w = size.width;
48778 var h = size.height;
48783 //var x = 0, y = 0;
48785 var rs = this.regions;
48786 var north = rs["north"];
48787 var south = rs["south"];
48788 var west = rs["west"];
48789 var east = rs["east"];
48790 var center = rs["center"];
48791 //if(this.hideOnLayout){ // not supported anymore
48792 //c.el.setStyle("display", "none");
48794 if(north && north.isVisible()){
48795 var b = north.getBox();
48796 var m = north.getMargins();
48797 b.width = w - (m.left+m.right);
48800 centerY = b.height + b.y + m.bottom;
48801 centerH -= centerY;
48802 north.updateBox(this.safeBox(b));
48804 if(south && south.isVisible()){
48805 var b = south.getBox();
48806 var m = south.getMargins();
48807 b.width = w - (m.left+m.right);
48809 var totalHeight = (b.height + m.top + m.bottom);
48810 b.y = h - totalHeight + m.top;
48811 centerH -= totalHeight;
48812 south.updateBox(this.safeBox(b));
48814 if(west && west.isVisible()){
48815 var b = west.getBox();
48816 var m = west.getMargins();
48817 b.height = centerH - (m.top+m.bottom);
48819 b.y = centerY + m.top;
48820 var totalWidth = (b.width + m.left + m.right);
48821 centerX += totalWidth;
48822 centerW -= totalWidth;
48823 west.updateBox(this.safeBox(b));
48825 if(east && east.isVisible()){
48826 var b = east.getBox();
48827 var m = east.getMargins();
48828 b.height = centerH - (m.top+m.bottom);
48829 var totalWidth = (b.width + m.left + m.right);
48830 b.x = w - totalWidth + m.left;
48831 b.y = centerY + m.top;
48832 centerW -= totalWidth;
48833 east.updateBox(this.safeBox(b));
48836 var m = center.getMargins();
48838 x: centerX + m.left,
48839 y: centerY + m.top,
48840 width: centerW - (m.left+m.right),
48841 height: centerH - (m.top+m.bottom)
48843 //if(this.hideOnLayout){
48844 //center.el.setStyle("display", "block");
48846 center.updateBox(this.safeBox(centerBox));
48849 this.fireEvent("layout", this);
48853 safeBox : function(box){
48854 box.width = Math.max(0, box.width);
48855 box.height = Math.max(0, box.height);
48860 * Adds a ContentPanel (or subclass) to this layout.
48861 * @param {String} target The target region key (north, south, east, west or center).
48862 * @param {Roo.ContentPanel} panel The panel to add
48863 * @return {Roo.ContentPanel} The added panel
48865 add : function(target, panel){
48867 target = target.toLowerCase();
48868 return this.regions[target].add(panel);
48872 * Remove a ContentPanel (or subclass) to this layout.
48873 * @param {String} target The target region key (north, south, east, west or center).
48874 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
48875 * @return {Roo.ContentPanel} The removed panel
48877 remove : function(target, panel){
48878 target = target.toLowerCase();
48879 return this.regions[target].remove(panel);
48883 * Searches all regions for a panel with the specified id
48884 * @param {String} panelId
48885 * @return {Roo.ContentPanel} The panel or null if it wasn't found
48887 findPanel : function(panelId){
48888 var rs = this.regions;
48889 for(var target in rs){
48890 if(typeof rs[target] != "function"){
48891 var p = rs[target].getPanel(panelId);
48901 * Searches all regions for a panel with the specified id and activates (shows) it.
48902 * @param {String/ContentPanel} panelId The panels id or the panel itself
48903 * @return {Roo.ContentPanel} The shown panel or null
48905 showPanel : function(panelId) {
48906 var rs = this.regions;
48907 for(var target in rs){
48908 var r = rs[target];
48909 if(typeof r != "function"){
48910 if(r.hasPanel(panelId)){
48911 return r.showPanel(panelId);
48919 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
48920 * @param {Roo.state.Provider} provider (optional) An alternate state provider
48922 restoreState : function(provider){
48924 provider = Roo.state.Manager;
48926 var sm = new Roo.LayoutStateManager();
48927 sm.init(this, provider);
48931 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
48932 * object should contain properties for each region to add ContentPanels to, and each property's value should be
48933 * a valid ContentPanel config object. Example:
48935 // Create the main layout
48936 var layout = new Roo.BorderLayout('main-ct', {
48947 // Create and add multiple ContentPanels at once via configs
48950 id: 'source-files',
48952 title:'Ext Source Files',
48965 * @param {Object} regions An object containing ContentPanel configs by region name
48967 batchAdd : function(regions){
48968 this.beginUpdate();
48969 for(var rname in regions){
48970 var lr = this.regions[rname];
48972 this.addTypedPanels(lr, regions[rname]);
48979 addTypedPanels : function(lr, ps){
48980 if(typeof ps == 'string'){
48981 lr.add(new Roo.ContentPanel(ps));
48983 else if(ps instanceof Array){
48984 for(var i =0, len = ps.length; i < len; i++){
48985 this.addTypedPanels(lr, ps[i]);
48988 else if(!ps.events){ // raw config?
48990 delete ps.el; // prevent conflict
48991 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
48993 else { // panel object assumed!
48998 * Adds a xtype elements to the layout.
49002 xtype : 'ContentPanel',
49009 xtype : 'NestedLayoutPanel',
49015 items : [ ... list of content panels or nested layout panels.. ]
49019 * @param {Object} cfg Xtype definition of item to add.
49021 addxtype : function(cfg)
49023 // basically accepts a pannel...
49024 // can accept a layout region..!?!?
49025 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49027 if (!cfg.xtype.match(/Panel$/)) {
49032 if (typeof(cfg.region) == 'undefined') {
49033 Roo.log("Failed to add Panel, region was not set");
49037 var region = cfg.region;
49043 xitems = cfg.items;
49050 case 'ContentPanel': // ContentPanel (el, cfg)
49051 case 'ScrollPanel': // ContentPanel (el, cfg)
49053 if(cfg.autoCreate) {
49054 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49056 var el = this.el.createChild();
49057 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49060 this.add(region, ret);
49064 case 'TreePanel': // our new panel!
49065 cfg.el = this.el.createChild();
49066 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49067 this.add(region, ret);
49070 case 'NestedLayoutPanel':
49071 // create a new Layout (which is a Border Layout...
49072 var el = this.el.createChild();
49073 var clayout = cfg.layout;
49075 clayout.items = clayout.items || [];
49076 // replace this exitems with the clayout ones..
49077 xitems = clayout.items;
49080 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49081 cfg.background = false;
49083 var layout = new Roo.BorderLayout(el, clayout);
49085 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49086 //console.log('adding nested layout panel ' + cfg.toSource());
49087 this.add(region, ret);
49088 nb = {}; /// find first...
49093 // needs grid and region
49095 //var el = this.getRegion(region).el.createChild();
49096 var el = this.el.createChild();
49097 // create the grid first...
49099 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49101 if (region == 'center' && this.active ) {
49102 cfg.background = false;
49104 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49106 this.add(region, ret);
49107 if (cfg.background) {
49108 ret.on('activate', function(gp) {
49109 if (!gp.grid.rendered) {
49124 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49126 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49127 this.add(region, ret);
49130 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49134 // GridPanel (grid, cfg)
49137 this.beginUpdate();
49141 Roo.each(xitems, function(i) {
49142 region = nb && i.region ? i.region : false;
49144 var add = ret.addxtype(i);
49147 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49148 if (!i.background) {
49149 abn[region] = nb[region] ;
49156 // make the last non-background panel active..
49157 //if (nb) { Roo.log(abn); }
49160 for(var r in abn) {
49161 region = this.getRegion(r);
49163 // tried using nb[r], but it does not work..
49165 region.showPanel(abn[r]);
49176 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49177 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49178 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49179 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49182 var CP = Roo.ContentPanel;
49184 var layout = Roo.BorderLayout.create({
49188 panels: [new CP("north", "North")]
49197 panels: [new CP("west", {title: "West"})]
49206 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49215 panels: [new CP("south", {title: "South", closable: true})]
49222 preferredTabWidth: 150,
49224 new CP("center1", {title: "Close Me", closable: true}),
49225 new CP("center2", {title: "Center Panel", closable: false})
49230 layout.getRegion("center").showPanel("center1");
49235 Roo.BorderLayout.create = function(config, targetEl){
49236 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49237 layout.beginUpdate();
49238 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49239 for(var j = 0, jlen = regions.length; j < jlen; j++){
49240 var lr = regions[j];
49241 if(layout.regions[lr] && config[lr].panels){
49242 var r = layout.regions[lr];
49243 var ps = config[lr].panels;
49244 layout.addTypedPanels(r, ps);
49247 layout.endUpdate();
49252 Roo.BorderLayout.RegionFactory = {
49254 validRegions : ["north","south","east","west","center"],
49257 create : function(target, mgr, config){
49258 target = target.toLowerCase();
49259 if(config.lightweight || config.basic){
49260 return new Roo.BasicLayoutRegion(mgr, config, target);
49264 return new Roo.NorthLayoutRegion(mgr, config);
49266 return new Roo.SouthLayoutRegion(mgr, config);
49268 return new Roo.EastLayoutRegion(mgr, config);
49270 return new Roo.WestLayoutRegion(mgr, config);
49272 return new Roo.CenterLayoutRegion(mgr, config);
49274 throw 'Layout region "'+target+'" not supported.';
49278 * Ext JS Library 1.1.1
49279 * Copyright(c) 2006-2007, Ext JS, LLC.
49281 * Originally Released Under LGPL - original licence link has changed is not relivant.
49284 * <script type="text/javascript">
49288 * @class Roo.BasicLayoutRegion
49289 * @extends Roo.util.Observable
49290 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49291 * and does not have a titlebar, tabs or any other features. All it does is size and position
49292 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49294 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49296 this.position = pos;
49299 * @scope Roo.BasicLayoutRegion
49303 * @event beforeremove
49304 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49305 * @param {Roo.LayoutRegion} this
49306 * @param {Roo.ContentPanel} panel The panel
49307 * @param {Object} e The cancel event object
49309 "beforeremove" : true,
49311 * @event invalidated
49312 * Fires when the layout for this region is changed.
49313 * @param {Roo.LayoutRegion} this
49315 "invalidated" : true,
49317 * @event visibilitychange
49318 * Fires when this region is shown or hidden
49319 * @param {Roo.LayoutRegion} this
49320 * @param {Boolean} visibility true or false
49322 "visibilitychange" : true,
49324 * @event paneladded
49325 * Fires when a panel is added.
49326 * @param {Roo.LayoutRegion} this
49327 * @param {Roo.ContentPanel} panel The panel
49329 "paneladded" : true,
49331 * @event panelremoved
49332 * Fires when a panel is removed.
49333 * @param {Roo.LayoutRegion} this
49334 * @param {Roo.ContentPanel} panel The panel
49336 "panelremoved" : true,
49339 * Fires when this region is collapsed.
49340 * @param {Roo.LayoutRegion} this
49342 "collapsed" : true,
49345 * Fires when this region is expanded.
49346 * @param {Roo.LayoutRegion} this
49351 * Fires when this region is slid into view.
49352 * @param {Roo.LayoutRegion} this
49354 "slideshow" : true,
49357 * Fires when this region slides out of view.
49358 * @param {Roo.LayoutRegion} this
49360 "slidehide" : true,
49362 * @event panelactivated
49363 * Fires when a panel is activated.
49364 * @param {Roo.LayoutRegion} this
49365 * @param {Roo.ContentPanel} panel The activated panel
49367 "panelactivated" : true,
49370 * Fires when the user resizes this region.
49371 * @param {Roo.LayoutRegion} this
49372 * @param {Number} newSize The new size (width for east/west, height for north/south)
49376 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49377 this.panels = new Roo.util.MixedCollection();
49378 this.panels.getKey = this.getPanelId.createDelegate(this);
49380 this.activePanel = null;
49381 // ensure listeners are added...
49383 if (config.listeners || config.events) {
49384 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49385 listeners : config.listeners || {},
49386 events : config.events || {}
49390 if(skipConfig !== true){
49391 this.applyConfig(config);
49395 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49396 getPanelId : function(p){
49400 applyConfig : function(config){
49401 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49402 this.config = config;
49407 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49408 * the width, for horizontal (north, south) the height.
49409 * @param {Number} newSize The new width or height
49411 resizeTo : function(newSize){
49412 var el = this.el ? this.el :
49413 (this.activePanel ? this.activePanel.getEl() : null);
49415 switch(this.position){
49418 el.setWidth(newSize);
49419 this.fireEvent("resized", this, newSize);
49423 el.setHeight(newSize);
49424 this.fireEvent("resized", this, newSize);
49430 getBox : function(){
49431 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
49434 getMargins : function(){
49435 return this.margins;
49438 updateBox : function(box){
49440 var el = this.activePanel.getEl();
49441 el.dom.style.left = box.x + "px";
49442 el.dom.style.top = box.y + "px";
49443 this.activePanel.setSize(box.width, box.height);
49447 * Returns the container element for this region.
49448 * @return {Roo.Element}
49450 getEl : function(){
49451 return this.activePanel;
49455 * Returns true if this region is currently visible.
49456 * @return {Boolean}
49458 isVisible : function(){
49459 return this.activePanel ? true : false;
49462 setActivePanel : function(panel){
49463 panel = this.getPanel(panel);
49464 if(this.activePanel && this.activePanel != panel){
49465 this.activePanel.setActiveState(false);
49466 this.activePanel.getEl().setLeftTop(-10000,-10000);
49468 this.activePanel = panel;
49469 panel.setActiveState(true);
49471 panel.setSize(this.box.width, this.box.height);
49473 this.fireEvent("panelactivated", this, panel);
49474 this.fireEvent("invalidated");
49478 * Show the specified panel.
49479 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
49480 * @return {Roo.ContentPanel} The shown panel or null
49482 showPanel : function(panel){
49483 if(panel = this.getPanel(panel)){
49484 this.setActivePanel(panel);
49490 * Get the active panel for this region.
49491 * @return {Roo.ContentPanel} The active panel or null
49493 getActivePanel : function(){
49494 return this.activePanel;
49498 * Add the passed ContentPanel(s)
49499 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49500 * @return {Roo.ContentPanel} The panel added (if only one was added)
49502 add : function(panel){
49503 if(arguments.length > 1){
49504 for(var i = 0, len = arguments.length; i < len; i++) {
49505 this.add(arguments[i]);
49509 if(this.hasPanel(panel)){
49510 this.showPanel(panel);
49513 var el = panel.getEl();
49514 if(el.dom.parentNode != this.mgr.el.dom){
49515 this.mgr.el.dom.appendChild(el.dom);
49517 if(panel.setRegion){
49518 panel.setRegion(this);
49520 this.panels.add(panel);
49521 el.setStyle("position", "absolute");
49522 if(!panel.background){
49523 this.setActivePanel(panel);
49524 if(this.config.initialSize && this.panels.getCount()==1){
49525 this.resizeTo(this.config.initialSize);
49528 this.fireEvent("paneladded", this, panel);
49533 * Returns true if the panel is in this region.
49534 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49535 * @return {Boolean}
49537 hasPanel : function(panel){
49538 if(typeof panel == "object"){ // must be panel obj
49539 panel = panel.getId();
49541 return this.getPanel(panel) ? true : false;
49545 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49546 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49547 * @param {Boolean} preservePanel Overrides the config preservePanel option
49548 * @return {Roo.ContentPanel} The panel that was removed
49550 remove : function(panel, preservePanel){
49551 panel = this.getPanel(panel);
49556 this.fireEvent("beforeremove", this, panel, e);
49557 if(e.cancel === true){
49560 var panelId = panel.getId();
49561 this.panels.removeKey(panelId);
49566 * Returns the panel specified or null if it's not in this region.
49567 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49568 * @return {Roo.ContentPanel}
49570 getPanel : function(id){
49571 if(typeof id == "object"){ // must be panel obj
49574 return this.panels.get(id);
49578 * Returns this regions position (north/south/east/west/center).
49581 getPosition: function(){
49582 return this.position;
49586 * Ext JS Library 1.1.1
49587 * Copyright(c) 2006-2007, Ext JS, LLC.
49589 * Originally Released Under LGPL - original licence link has changed is not relivant.
49592 * <script type="text/javascript">
49596 * @class Roo.LayoutRegion
49597 * @extends Roo.BasicLayoutRegion
49598 * This class represents a region in a layout manager.
49599 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
49600 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
49601 * @cfg {Boolean} floatable False to disable floating (defaults to true)
49602 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
49603 * @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})
49604 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
49605 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
49606 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
49607 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
49608 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
49609 * @cfg {String} title The title for the region (overrides panel titles)
49610 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
49611 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
49612 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
49613 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
49614 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
49615 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
49616 * the space available, similar to FireFox 1.5 tabs (defaults to false)
49617 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
49618 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
49619 * @cfg {Boolean} showPin True to show a pin button
49620 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
49621 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
49622 * @cfg {Boolean} disableTabTips True to disable tab tooltips
49623 * @cfg {Number} width For East/West panels
49624 * @cfg {Number} height For North/South panels
49625 * @cfg {Boolean} split To show the splitter
49626 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
49628 Roo.LayoutRegion = function(mgr, config, pos){
49629 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
49630 var dh = Roo.DomHelper;
49631 /** This region's container element
49632 * @type Roo.Element */
49633 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
49634 /** This region's title element
49635 * @type Roo.Element */
49637 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
49638 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
49639 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
49641 this.titleEl.enableDisplayMode();
49642 /** This region's title text element
49643 * @type HTMLElement */
49644 this.titleTextEl = this.titleEl.dom.firstChild;
49645 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
49646 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
49647 this.closeBtn.enableDisplayMode();
49648 this.closeBtn.on("click", this.closeClicked, this);
49649 this.closeBtn.hide();
49651 this.createBody(config);
49652 this.visible = true;
49653 this.collapsed = false;
49655 if(config.hideWhenEmpty){
49657 this.on("paneladded", this.validateVisibility, this);
49658 this.on("panelremoved", this.validateVisibility, this);
49660 this.applyConfig(config);
49663 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
49665 createBody : function(){
49666 /** This region's body element
49667 * @type Roo.Element */
49668 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
49671 applyConfig : function(c){
49672 if(c.collapsible && this.position != "center" && !this.collapsedEl){
49673 var dh = Roo.DomHelper;
49674 if(c.titlebar !== false){
49675 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
49676 this.collapseBtn.on("click", this.collapse, this);
49677 this.collapseBtn.enableDisplayMode();
49679 if(c.showPin === true || this.showPin){
49680 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
49681 this.stickBtn.enableDisplayMode();
49682 this.stickBtn.on("click", this.expand, this);
49683 this.stickBtn.hide();
49686 /** This region's collapsed element
49687 * @type Roo.Element */
49688 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
49689 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
49691 if(c.floatable !== false){
49692 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
49693 this.collapsedEl.on("click", this.collapseClick, this);
49696 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
49697 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
49698 id: "message", unselectable: "on", style:{"float":"left"}});
49699 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
49701 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
49702 this.expandBtn.on("click", this.expand, this);
49704 if(this.collapseBtn){
49705 this.collapseBtn.setVisible(c.collapsible == true);
49707 this.cmargins = c.cmargins || this.cmargins ||
49708 (this.position == "west" || this.position == "east" ?
49709 {top: 0, left: 2, right:2, bottom: 0} :
49710 {top: 2, left: 0, right:0, bottom: 2});
49711 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49712 this.bottomTabs = c.tabPosition != "top";
49713 this.autoScroll = c.autoScroll || false;
49714 if(this.autoScroll){
49715 this.bodyEl.setStyle("overflow", "auto");
49717 this.bodyEl.setStyle("overflow", "hidden");
49719 //if(c.titlebar !== false){
49720 if((!c.titlebar && !c.title) || c.titlebar === false){
49721 this.titleEl.hide();
49723 this.titleEl.show();
49725 this.titleTextEl.innerHTML = c.title;
49729 this.duration = c.duration || .30;
49730 this.slideDuration = c.slideDuration || .45;
49733 this.collapse(true);
49740 * Returns true if this region is currently visible.
49741 * @return {Boolean}
49743 isVisible : function(){
49744 return this.visible;
49748 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
49749 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
49751 setCollapsedTitle : function(title){
49752 title = title || " ";
49753 if(this.collapsedTitleTextEl){
49754 this.collapsedTitleTextEl.innerHTML = title;
49758 getBox : function(){
49760 if(!this.collapsed){
49761 b = this.el.getBox(false, true);
49763 b = this.collapsedEl.getBox(false, true);
49768 getMargins : function(){
49769 return this.collapsed ? this.cmargins : this.margins;
49772 highlight : function(){
49773 this.el.addClass("x-layout-panel-dragover");
49776 unhighlight : function(){
49777 this.el.removeClass("x-layout-panel-dragover");
49780 updateBox : function(box){
49782 if(!this.collapsed){
49783 this.el.dom.style.left = box.x + "px";
49784 this.el.dom.style.top = box.y + "px";
49785 this.updateBody(box.width, box.height);
49787 this.collapsedEl.dom.style.left = box.x + "px";
49788 this.collapsedEl.dom.style.top = box.y + "px";
49789 this.collapsedEl.setSize(box.width, box.height);
49792 this.tabs.autoSizeTabs();
49796 updateBody : function(w, h){
49798 this.el.setWidth(w);
49799 w -= this.el.getBorderWidth("rl");
49800 if(this.config.adjustments){
49801 w += this.config.adjustments[0];
49805 this.el.setHeight(h);
49806 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
49807 h -= this.el.getBorderWidth("tb");
49808 if(this.config.adjustments){
49809 h += this.config.adjustments[1];
49811 this.bodyEl.setHeight(h);
49813 h = this.tabs.syncHeight(h);
49816 if(this.panelSize){
49817 w = w !== null ? w : this.panelSize.width;
49818 h = h !== null ? h : this.panelSize.height;
49820 if(this.activePanel){
49821 var el = this.activePanel.getEl();
49822 w = w !== null ? w : el.getWidth();
49823 h = h !== null ? h : el.getHeight();
49824 this.panelSize = {width: w, height: h};
49825 this.activePanel.setSize(w, h);
49827 if(Roo.isIE && this.tabs){
49828 this.tabs.el.repaint();
49833 * Returns the container element for this region.
49834 * @return {Roo.Element}
49836 getEl : function(){
49841 * Hides this region.
49844 if(!this.collapsed){
49845 this.el.dom.style.left = "-2000px";
49848 this.collapsedEl.dom.style.left = "-2000px";
49849 this.collapsedEl.hide();
49851 this.visible = false;
49852 this.fireEvent("visibilitychange", this, false);
49856 * Shows this region if it was previously hidden.
49859 if(!this.collapsed){
49862 this.collapsedEl.show();
49864 this.visible = true;
49865 this.fireEvent("visibilitychange", this, true);
49868 closeClicked : function(){
49869 if(this.activePanel){
49870 this.remove(this.activePanel);
49874 collapseClick : function(e){
49876 e.stopPropagation();
49879 e.stopPropagation();
49885 * Collapses this region.
49886 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
49888 collapse : function(skipAnim){
49889 if(this.collapsed) return;
49890 this.collapsed = true;
49892 this.split.el.hide();
49894 if(this.config.animate && skipAnim !== true){
49895 this.fireEvent("invalidated", this);
49896 this.animateCollapse();
49898 this.el.setLocation(-20000,-20000);
49900 this.collapsedEl.show();
49901 this.fireEvent("collapsed", this);
49902 this.fireEvent("invalidated", this);
49906 animateCollapse : function(){
49911 * Expands this region if it was previously collapsed.
49912 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
49913 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
49915 expand : function(e, skipAnim){
49916 if(e) e.stopPropagation();
49917 if(!this.collapsed || this.el.hasActiveFx()) return;
49919 this.afterSlideIn();
49922 this.collapsed = false;
49923 if(this.config.animate && skipAnim !== true){
49924 this.animateExpand();
49928 this.split.el.show();
49930 this.collapsedEl.setLocation(-2000,-2000);
49931 this.collapsedEl.hide();
49932 this.fireEvent("invalidated", this);
49933 this.fireEvent("expanded", this);
49937 animateExpand : function(){
49941 initTabs : function()
49943 this.bodyEl.setStyle("overflow", "hidden");
49944 var ts = new Roo.TabPanel(
49947 tabPosition: this.bottomTabs ? 'bottom' : 'top',
49948 disableTooltips: this.config.disableTabTips,
49949 toolbar : this.config.toolbar
49952 if(this.config.hideTabs){
49953 ts.stripWrap.setDisplayed(false);
49956 ts.resizeTabs = this.config.resizeTabs === true;
49957 ts.minTabWidth = this.config.minTabWidth || 40;
49958 ts.maxTabWidth = this.config.maxTabWidth || 250;
49959 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
49960 ts.monitorResize = false;
49961 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49962 ts.bodyEl.addClass('x-layout-tabs-body');
49963 this.panels.each(this.initPanelAsTab, this);
49966 initPanelAsTab : function(panel){
49967 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
49968 this.config.closeOnTab && panel.isClosable());
49969 if(panel.tabTip !== undefined){
49970 ti.setTooltip(panel.tabTip);
49972 ti.on("activate", function(){
49973 this.setActivePanel(panel);
49975 if(this.config.closeOnTab){
49976 ti.on("beforeclose", function(t, e){
49978 this.remove(panel);
49984 updatePanelTitle : function(panel, title){
49985 if(this.activePanel == panel){
49986 this.updateTitle(title);
49989 var ti = this.tabs.getTab(panel.getEl().id);
49991 if(panel.tabTip !== undefined){
49992 ti.setTooltip(panel.tabTip);
49997 updateTitle : function(title){
49998 if(this.titleTextEl && !this.config.title){
49999 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50003 setActivePanel : function(panel){
50004 panel = this.getPanel(panel);
50005 if(this.activePanel && this.activePanel != panel){
50006 this.activePanel.setActiveState(false);
50008 this.activePanel = panel;
50009 panel.setActiveState(true);
50010 if(this.panelSize){
50011 panel.setSize(this.panelSize.width, this.panelSize.height);
50014 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50016 this.updateTitle(panel.getTitle());
50018 this.fireEvent("invalidated", this);
50020 this.fireEvent("panelactivated", this, panel);
50024 * Shows the specified panel.
50025 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50026 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50028 showPanel : function(panel){
50029 if(panel = this.getPanel(panel)){
50031 var tab = this.tabs.getTab(panel.getEl().id);
50032 if(tab.isHidden()){
50033 this.tabs.unhideTab(tab.id);
50037 this.setActivePanel(panel);
50044 * Get the active panel for this region.
50045 * @return {Roo.ContentPanel} The active panel or null
50047 getActivePanel : function(){
50048 return this.activePanel;
50051 validateVisibility : function(){
50052 if(this.panels.getCount() < 1){
50053 this.updateTitle(" ");
50054 this.closeBtn.hide();
50057 if(!this.isVisible()){
50064 * Adds the passed ContentPanel(s) to this region.
50065 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50066 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50068 add : function(panel){
50069 if(arguments.length > 1){
50070 for(var i = 0, len = arguments.length; i < len; i++) {
50071 this.add(arguments[i]);
50075 if(this.hasPanel(panel)){
50076 this.showPanel(panel);
50079 panel.setRegion(this);
50080 this.panels.add(panel);
50081 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50082 this.bodyEl.dom.appendChild(panel.getEl().dom);
50083 if(panel.background !== true){
50084 this.setActivePanel(panel);
50086 this.fireEvent("paneladded", this, panel);
50092 this.initPanelAsTab(panel);
50094 if(panel.background !== true){
50095 this.tabs.activate(panel.getEl().id);
50097 this.fireEvent("paneladded", this, panel);
50102 * Hides the tab for the specified panel.
50103 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50105 hidePanel : function(panel){
50106 if(this.tabs && (panel = this.getPanel(panel))){
50107 this.tabs.hideTab(panel.getEl().id);
50112 * Unhides the tab for a previously hidden panel.
50113 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50115 unhidePanel : function(panel){
50116 if(this.tabs && (panel = this.getPanel(panel))){
50117 this.tabs.unhideTab(panel.getEl().id);
50121 clearPanels : function(){
50122 while(this.panels.getCount() > 0){
50123 this.remove(this.panels.first());
50128 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50129 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50130 * @param {Boolean} preservePanel Overrides the config preservePanel option
50131 * @return {Roo.ContentPanel} The panel that was removed
50133 remove : function(panel, preservePanel){
50134 panel = this.getPanel(panel);
50139 this.fireEvent("beforeremove", this, panel, e);
50140 if(e.cancel === true){
50143 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50144 var panelId = panel.getId();
50145 this.panels.removeKey(panelId);
50147 document.body.appendChild(panel.getEl().dom);
50150 this.tabs.removeTab(panel.getEl().id);
50151 }else if (!preservePanel){
50152 this.bodyEl.dom.removeChild(panel.getEl().dom);
50154 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50155 var p = this.panels.first();
50156 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50157 tempEl.appendChild(p.getEl().dom);
50158 this.bodyEl.update("");
50159 this.bodyEl.dom.appendChild(p.getEl().dom);
50161 this.updateTitle(p.getTitle());
50163 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50164 this.setActivePanel(p);
50166 panel.setRegion(null);
50167 if(this.activePanel == panel){
50168 this.activePanel = null;
50170 if(this.config.autoDestroy !== false && preservePanel !== true){
50171 try{panel.destroy();}catch(e){}
50173 this.fireEvent("panelremoved", this, panel);
50178 * Returns the TabPanel component used by this region
50179 * @return {Roo.TabPanel}
50181 getTabs : function(){
50185 createTool : function(parentEl, className){
50186 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50187 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50188 btn.addClassOnOver("x-layout-tools-button-over");
50193 * Ext JS Library 1.1.1
50194 * Copyright(c) 2006-2007, Ext JS, LLC.
50196 * Originally Released Under LGPL - original licence link has changed is not relivant.
50199 * <script type="text/javascript">
50205 * @class Roo.SplitLayoutRegion
50206 * @extends Roo.LayoutRegion
50207 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50209 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50210 this.cursor = cursor;
50211 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50214 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50215 splitTip : "Drag to resize.",
50216 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50217 useSplitTips : false,
50219 applyConfig : function(config){
50220 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50223 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50224 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50225 /** The SplitBar for this region
50226 * @type Roo.SplitBar */
50227 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50228 this.split.on("moved", this.onSplitMove, this);
50229 this.split.useShim = config.useShim === true;
50230 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50231 if(this.useSplitTips){
50232 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50234 if(config.collapsible){
50235 this.split.el.on("dblclick", this.collapse, this);
50238 if(typeof config.minSize != "undefined"){
50239 this.split.minSize = config.minSize;
50241 if(typeof config.maxSize != "undefined"){
50242 this.split.maxSize = config.maxSize;
50244 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50245 this.hideSplitter();
50250 getHMaxSize : function(){
50251 var cmax = this.config.maxSize || 10000;
50252 var center = this.mgr.getRegion("center");
50253 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50256 getVMaxSize : function(){
50257 var cmax = this.config.maxSize || 10000;
50258 var center = this.mgr.getRegion("center");
50259 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50262 onSplitMove : function(split, newSize){
50263 this.fireEvent("resized", this, newSize);
50267 * Returns the {@link Roo.SplitBar} for this region.
50268 * @return {Roo.SplitBar}
50270 getSplitBar : function(){
50275 this.hideSplitter();
50276 Roo.SplitLayoutRegion.superclass.hide.call(this);
50279 hideSplitter : function(){
50281 this.split.el.setLocation(-2000,-2000);
50282 this.split.el.hide();
50288 this.split.el.show();
50290 Roo.SplitLayoutRegion.superclass.show.call(this);
50293 beforeSlide: function(){
50294 if(Roo.isGecko){// firefox overflow auto bug workaround
50295 this.bodyEl.clip();
50296 if(this.tabs) this.tabs.bodyEl.clip();
50297 if(this.activePanel){
50298 this.activePanel.getEl().clip();
50300 if(this.activePanel.beforeSlide){
50301 this.activePanel.beforeSlide();
50307 afterSlide : function(){
50308 if(Roo.isGecko){// firefox overflow auto bug workaround
50309 this.bodyEl.unclip();
50310 if(this.tabs) this.tabs.bodyEl.unclip();
50311 if(this.activePanel){
50312 this.activePanel.getEl().unclip();
50313 if(this.activePanel.afterSlide){
50314 this.activePanel.afterSlide();
50320 initAutoHide : function(){
50321 if(this.autoHide !== false){
50322 if(!this.autoHideHd){
50323 var st = new Roo.util.DelayedTask(this.slideIn, this);
50324 this.autoHideHd = {
50325 "mouseout": function(e){
50326 if(!e.within(this.el, true)){
50330 "mouseover" : function(e){
50336 this.el.on(this.autoHideHd);
50340 clearAutoHide : function(){
50341 if(this.autoHide !== false){
50342 this.el.un("mouseout", this.autoHideHd.mouseout);
50343 this.el.un("mouseover", this.autoHideHd.mouseover);
50347 clearMonitor : function(){
50348 Roo.get(document).un("click", this.slideInIf, this);
50351 // these names are backwards but not changed for compat
50352 slideOut : function(){
50353 if(this.isSlid || this.el.hasActiveFx()){
50356 this.isSlid = true;
50357 if(this.collapseBtn){
50358 this.collapseBtn.hide();
50360 this.closeBtnState = this.closeBtn.getStyle('display');
50361 this.closeBtn.hide();
50363 this.stickBtn.show();
50366 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50367 this.beforeSlide();
50368 this.el.setStyle("z-index", 10001);
50369 this.el.slideIn(this.getSlideAnchor(), {
50370 callback: function(){
50372 this.initAutoHide();
50373 Roo.get(document).on("click", this.slideInIf, this);
50374 this.fireEvent("slideshow", this);
50381 afterSlideIn : function(){
50382 this.clearAutoHide();
50383 this.isSlid = false;
50384 this.clearMonitor();
50385 this.el.setStyle("z-index", "");
50386 if(this.collapseBtn){
50387 this.collapseBtn.show();
50389 this.closeBtn.setStyle('display', this.closeBtnState);
50391 this.stickBtn.hide();
50393 this.fireEvent("slidehide", this);
50396 slideIn : function(cb){
50397 if(!this.isSlid || this.el.hasActiveFx()){
50401 this.isSlid = false;
50402 this.beforeSlide();
50403 this.el.slideOut(this.getSlideAnchor(), {
50404 callback: function(){
50405 this.el.setLeftTop(-10000, -10000);
50407 this.afterSlideIn();
50415 slideInIf : function(e){
50416 if(!e.within(this.el)){
50421 animateCollapse : function(){
50422 this.beforeSlide();
50423 this.el.setStyle("z-index", 20000);
50424 var anchor = this.getSlideAnchor();
50425 this.el.slideOut(anchor, {
50426 callback : function(){
50427 this.el.setStyle("z-index", "");
50428 this.collapsedEl.slideIn(anchor, {duration:.3});
50430 this.el.setLocation(-10000,-10000);
50432 this.fireEvent("collapsed", this);
50439 animateExpand : function(){
50440 this.beforeSlide();
50441 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
50442 this.el.setStyle("z-index", 20000);
50443 this.collapsedEl.hide({
50446 this.el.slideIn(this.getSlideAnchor(), {
50447 callback : function(){
50448 this.el.setStyle("z-index", "");
50451 this.split.el.show();
50453 this.fireEvent("invalidated", this);
50454 this.fireEvent("expanded", this);
50482 getAnchor : function(){
50483 return this.anchors[this.position];
50486 getCollapseAnchor : function(){
50487 return this.canchors[this.position];
50490 getSlideAnchor : function(){
50491 return this.sanchors[this.position];
50494 getAlignAdj : function(){
50495 var cm = this.cmargins;
50496 switch(this.position){
50512 getExpandAdj : function(){
50513 var c = this.collapsedEl, cm = this.cmargins;
50514 switch(this.position){
50516 return [-(cm.right+c.getWidth()+cm.left), 0];
50519 return [cm.right+c.getWidth()+cm.left, 0];
50522 return [0, -(cm.top+cm.bottom+c.getHeight())];
50525 return [0, cm.top+cm.bottom+c.getHeight()];
50531 * Ext JS Library 1.1.1
50532 * Copyright(c) 2006-2007, Ext JS, LLC.
50534 * Originally Released Under LGPL - original licence link has changed is not relivant.
50537 * <script type="text/javascript">
50540 * These classes are private internal classes
50542 Roo.CenterLayoutRegion = function(mgr, config){
50543 Roo.LayoutRegion.call(this, mgr, config, "center");
50544 this.visible = true;
50545 this.minWidth = config.minWidth || 20;
50546 this.minHeight = config.minHeight || 20;
50549 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
50551 // center panel can't be hidden
50555 // center panel can't be hidden
50558 getMinWidth: function(){
50559 return this.minWidth;
50562 getMinHeight: function(){
50563 return this.minHeight;
50568 Roo.NorthLayoutRegion = function(mgr, config){
50569 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
50571 this.split.placement = Roo.SplitBar.TOP;
50572 this.split.orientation = Roo.SplitBar.VERTICAL;
50573 this.split.el.addClass("x-layout-split-v");
50575 var size = config.initialSize || config.height;
50576 if(typeof size != "undefined"){
50577 this.el.setHeight(size);
50580 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
50581 orientation: Roo.SplitBar.VERTICAL,
50582 getBox : function(){
50583 if(this.collapsed){
50584 return this.collapsedEl.getBox();
50586 var box = this.el.getBox();
50588 box.height += this.split.el.getHeight();
50593 updateBox : function(box){
50594 if(this.split && !this.collapsed){
50595 box.height -= this.split.el.getHeight();
50596 this.split.el.setLeft(box.x);
50597 this.split.el.setTop(box.y+box.height);
50598 this.split.el.setWidth(box.width);
50600 if(this.collapsed){
50601 this.updateBody(box.width, null);
50603 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50607 Roo.SouthLayoutRegion = function(mgr, config){
50608 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
50610 this.split.placement = Roo.SplitBar.BOTTOM;
50611 this.split.orientation = Roo.SplitBar.VERTICAL;
50612 this.split.el.addClass("x-layout-split-v");
50614 var size = config.initialSize || config.height;
50615 if(typeof size != "undefined"){
50616 this.el.setHeight(size);
50619 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
50620 orientation: Roo.SplitBar.VERTICAL,
50621 getBox : function(){
50622 if(this.collapsed){
50623 return this.collapsedEl.getBox();
50625 var box = this.el.getBox();
50627 var sh = this.split.el.getHeight();
50634 updateBox : function(box){
50635 if(this.split && !this.collapsed){
50636 var sh = this.split.el.getHeight();
50639 this.split.el.setLeft(box.x);
50640 this.split.el.setTop(box.y-sh);
50641 this.split.el.setWidth(box.width);
50643 if(this.collapsed){
50644 this.updateBody(box.width, null);
50646 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50650 Roo.EastLayoutRegion = function(mgr, config){
50651 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
50653 this.split.placement = Roo.SplitBar.RIGHT;
50654 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50655 this.split.el.addClass("x-layout-split-h");
50657 var size = config.initialSize || config.width;
50658 if(typeof size != "undefined"){
50659 this.el.setWidth(size);
50662 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
50663 orientation: Roo.SplitBar.HORIZONTAL,
50664 getBox : function(){
50665 if(this.collapsed){
50666 return this.collapsedEl.getBox();
50668 var box = this.el.getBox();
50670 var sw = this.split.el.getWidth();
50677 updateBox : function(box){
50678 if(this.split && !this.collapsed){
50679 var sw = this.split.el.getWidth();
50681 this.split.el.setLeft(box.x);
50682 this.split.el.setTop(box.y);
50683 this.split.el.setHeight(box.height);
50686 if(this.collapsed){
50687 this.updateBody(null, box.height);
50689 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50693 Roo.WestLayoutRegion = function(mgr, config){
50694 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
50696 this.split.placement = Roo.SplitBar.LEFT;
50697 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50698 this.split.el.addClass("x-layout-split-h");
50700 var size = config.initialSize || config.width;
50701 if(typeof size != "undefined"){
50702 this.el.setWidth(size);
50705 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
50706 orientation: Roo.SplitBar.HORIZONTAL,
50707 getBox : function(){
50708 if(this.collapsed){
50709 return this.collapsedEl.getBox();
50711 var box = this.el.getBox();
50713 box.width += this.split.el.getWidth();
50718 updateBox : function(box){
50719 if(this.split && !this.collapsed){
50720 var sw = this.split.el.getWidth();
50722 this.split.el.setLeft(box.x+box.width);
50723 this.split.el.setTop(box.y);
50724 this.split.el.setHeight(box.height);
50726 if(this.collapsed){
50727 this.updateBody(null, box.height);
50729 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50734 * Ext JS Library 1.1.1
50735 * Copyright(c) 2006-2007, Ext JS, LLC.
50737 * Originally Released Under LGPL - original licence link has changed is not relivant.
50740 * <script type="text/javascript">
50745 * Private internal class for reading and applying state
50747 Roo.LayoutStateManager = function(layout){
50748 // default empty state
50757 Roo.LayoutStateManager.prototype = {
50758 init : function(layout, provider){
50759 this.provider = provider;
50760 var state = provider.get(layout.id+"-layout-state");
50762 var wasUpdating = layout.isUpdating();
50764 layout.beginUpdate();
50766 for(var key in state){
50767 if(typeof state[key] != "function"){
50768 var rstate = state[key];
50769 var r = layout.getRegion(key);
50772 r.resizeTo(rstate.size);
50774 if(rstate.collapsed == true){
50777 r.expand(null, true);
50783 layout.endUpdate();
50785 this.state = state;
50787 this.layout = layout;
50788 layout.on("regionresized", this.onRegionResized, this);
50789 layout.on("regioncollapsed", this.onRegionCollapsed, this);
50790 layout.on("regionexpanded", this.onRegionExpanded, this);
50793 storeState : function(){
50794 this.provider.set(this.layout.id+"-layout-state", this.state);
50797 onRegionResized : function(region, newSize){
50798 this.state[region.getPosition()].size = newSize;
50802 onRegionCollapsed : function(region){
50803 this.state[region.getPosition()].collapsed = true;
50807 onRegionExpanded : function(region){
50808 this.state[region.getPosition()].collapsed = false;
50813 * Ext JS Library 1.1.1
50814 * Copyright(c) 2006-2007, Ext JS, LLC.
50816 * Originally Released Under LGPL - original licence link has changed is not relivant.
50819 * <script type="text/javascript">
50822 * @class Roo.ContentPanel
50823 * @extends Roo.util.Observable
50824 * A basic ContentPanel element.
50825 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
50826 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
50827 * @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
50828 * @cfg {Boolean} closable True if the panel can be closed/removed
50829 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
50830 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
50831 * @cfg {Toolbar} toolbar A toolbar for this panel
50832 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
50833 * @cfg {String} title The title for this panel
50834 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
50835 * @cfg {String} url Calls {@link #setUrl} with this value
50836 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
50837 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
50838 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
50839 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
50842 * Create a new ContentPanel.
50843 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
50844 * @param {String/Object} config A string to set only the title or a config object
50845 * @param {String} content (optional) Set the HTML content for this panel
50846 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
50848 Roo.ContentPanel = function(el, config, content){
50852 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
50856 if (config && config.parentLayout) {
50857 el = config.parentLayout.el.createChild();
50860 if(el.autoCreate){ // xtype is available if this is called from factory
50864 this.el = Roo.get(el);
50865 if(!this.el && config && config.autoCreate){
50866 if(typeof config.autoCreate == "object"){
50867 if(!config.autoCreate.id){
50868 config.autoCreate.id = config.id||el;
50870 this.el = Roo.DomHelper.append(document.body,
50871 config.autoCreate, true);
50873 this.el = Roo.DomHelper.append(document.body,
50874 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
50877 this.closable = false;
50878 this.loaded = false;
50879 this.active = false;
50880 if(typeof config == "string"){
50881 this.title = config;
50883 Roo.apply(this, config);
50886 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
50887 this.wrapEl = this.el.wrap();
50888 this.toolbar.container = this.el.insertSibling(false, 'before');
50889 this.toolbar = new Roo.Toolbar(this.toolbar);
50892 // xtype created footer. - not sure if will work as we normally have to render first..
50893 if (this.footer && !this.footer.el && this.footer.xtype) {
50894 if (!this.wrapEl) {
50895 this.wrapEl = this.el.wrap();
50898 this.footer.container = this.wrapEl.createChild();
50900 this.footer = Roo.factory(this.footer, Roo);
50905 this.resizeEl = Roo.get(this.resizeEl, true);
50907 this.resizeEl = this.el;
50909 // handle view.xtype
50917 * Fires when this panel is activated.
50918 * @param {Roo.ContentPanel} this
50922 * @event deactivate
50923 * Fires when this panel is activated.
50924 * @param {Roo.ContentPanel} this
50926 "deactivate" : true,
50930 * Fires when this panel is resized if fitToFrame is true.
50931 * @param {Roo.ContentPanel} this
50932 * @param {Number} width The width after any component adjustments
50933 * @param {Number} height The height after any component adjustments
50939 * Fires when this tab is created
50940 * @param {Roo.ContentPanel} this
50951 if(this.autoScroll){
50952 this.resizeEl.setStyle("overflow", "auto");
50954 // fix randome scrolling
50955 this.el.on('scroll', function() {
50956 Roo.log('fix random scolling');
50957 this.scrollTo('top',0);
50960 content = content || this.content;
50962 this.setContent(content);
50964 if(config && config.url){
50965 this.setUrl(this.url, this.params, this.loadOnce);
50970 Roo.ContentPanel.superclass.constructor.call(this);
50972 if (this.view && typeof(this.view.xtype) != 'undefined') {
50973 this.view.el = this.el.appendChild(document.createElement("div"));
50974 this.view = Roo.factory(this.view);
50975 this.view.render && this.view.render(false, '');
50979 this.fireEvent('render', this);
50982 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
50984 setRegion : function(region){
50985 this.region = region;
50987 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
50989 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
50994 * Returns the toolbar for this Panel if one was configured.
50995 * @return {Roo.Toolbar}
50997 getToolbar : function(){
50998 return this.toolbar;
51001 setActiveState : function(active){
51002 this.active = active;
51004 this.fireEvent("deactivate", this);
51006 this.fireEvent("activate", this);
51010 * Updates this panel's element
51011 * @param {String} content The new content
51012 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51014 setContent : function(content, loadScripts){
51015 this.el.update(content, loadScripts);
51018 ignoreResize : function(w, h){
51019 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51022 this.lastSize = {width: w, height: h};
51027 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51028 * @return {Roo.UpdateManager} The UpdateManager
51030 getUpdateManager : function(){
51031 return this.el.getUpdateManager();
51034 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51035 * @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:
51038 url: "your-url.php",
51039 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51040 callback: yourFunction,
51041 scope: yourObject, //(optional scope)
51044 text: "Loading...",
51049 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51050 * 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.
51051 * @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}
51052 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51053 * @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.
51054 * @return {Roo.ContentPanel} this
51057 var um = this.el.getUpdateManager();
51058 um.update.apply(um, arguments);
51064 * 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.
51065 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51066 * @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)
51067 * @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)
51068 * @return {Roo.UpdateManager} The UpdateManager
51070 setUrl : function(url, params, loadOnce){
51071 if(this.refreshDelegate){
51072 this.removeListener("activate", this.refreshDelegate);
51074 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51075 this.on("activate", this.refreshDelegate);
51076 return this.el.getUpdateManager();
51079 _handleRefresh : function(url, params, loadOnce){
51080 if(!loadOnce || !this.loaded){
51081 var updater = this.el.getUpdateManager();
51082 updater.update(url, params, this._setLoaded.createDelegate(this));
51086 _setLoaded : function(){
51087 this.loaded = true;
51091 * Returns this panel's id
51094 getId : function(){
51099 * Returns this panel's element - used by regiosn to add.
51100 * @return {Roo.Element}
51102 getEl : function(){
51103 return this.wrapEl || this.el;
51106 adjustForComponents : function(width, height)
51108 //Roo.log('adjustForComponents ');
51109 if(this.resizeEl != this.el){
51110 width -= this.el.getFrameWidth('lr');
51111 height -= this.el.getFrameWidth('tb');
51114 var te = this.toolbar.getEl();
51115 height -= te.getHeight();
51116 te.setWidth(width);
51119 var te = this.footer.getEl();
51120 Roo.log("footer:" + te.getHeight());
51122 height -= te.getHeight();
51123 te.setWidth(width);
51127 if(this.adjustments){
51128 width += this.adjustments[0];
51129 height += this.adjustments[1];
51131 return {"width": width, "height": height};
51134 setSize : function(width, height){
51135 if(this.fitToFrame && !this.ignoreResize(width, height)){
51136 if(this.fitContainer && this.resizeEl != this.el){
51137 this.el.setSize(width, height);
51139 var size = this.adjustForComponents(width, height);
51140 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51141 this.fireEvent('resize', this, size.width, size.height);
51146 * Returns this panel's title
51149 getTitle : function(){
51154 * Set this panel's title
51155 * @param {String} title
51157 setTitle : function(title){
51158 this.title = title;
51160 this.region.updatePanelTitle(this, title);
51165 * Returns true is this panel was configured to be closable
51166 * @return {Boolean}
51168 isClosable : function(){
51169 return this.closable;
51172 beforeSlide : function(){
51174 this.resizeEl.clip();
51177 afterSlide : function(){
51179 this.resizeEl.unclip();
51183 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51184 * Will fail silently if the {@link #setUrl} method has not been called.
51185 * This does not activate the panel, just updates its content.
51187 refresh : function(){
51188 if(this.refreshDelegate){
51189 this.loaded = false;
51190 this.refreshDelegate();
51195 * Destroys this panel
51197 destroy : function(){
51198 this.el.removeAllListeners();
51199 var tempEl = document.createElement("span");
51200 tempEl.appendChild(this.el.dom);
51201 tempEl.innerHTML = "";
51207 * form - if the content panel contains a form - this is a reference to it.
51208 * @type {Roo.form.Form}
51212 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51213 * This contains a reference to it.
51219 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51229 * @param {Object} cfg Xtype definition of item to add.
51232 addxtype : function(cfg) {
51234 if (cfg.xtype.match(/^Form$/)) {
51237 //if (this.footer) {
51238 // el = this.footer.container.insertSibling(false, 'before');
51240 el = this.el.createChild();
51243 this.form = new Roo.form.Form(cfg);
51246 if ( this.form.allItems.length) this.form.render(el.dom);
51249 // should only have one of theses..
51250 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51251 // views.. should not be just added - used named prop 'view''
51253 cfg.el = this.el.appendChild(document.createElement("div"));
51256 var ret = new Roo.factory(cfg);
51258 ret.render && ret.render(false, ''); // render blank..
51267 * @class Roo.GridPanel
51268 * @extends Roo.ContentPanel
51270 * Create a new GridPanel.
51271 * @param {Roo.grid.Grid} grid The grid for this panel
51272 * @param {String/Object} config A string to set only the panel's title, or a config object
51274 Roo.GridPanel = function(grid, config){
51277 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51278 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51280 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51282 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51285 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51287 // xtype created footer. - not sure if will work as we normally have to render first..
51288 if (this.footer && !this.footer.el && this.footer.xtype) {
51290 this.footer.container = this.grid.getView().getFooterPanel(true);
51291 this.footer.dataSource = this.grid.dataSource;
51292 this.footer = Roo.factory(this.footer, Roo);
51296 grid.monitorWindowResize = false; // turn off autosizing
51297 grid.autoHeight = false;
51298 grid.autoWidth = false;
51300 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51303 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51304 getId : function(){
51305 return this.grid.id;
51309 * Returns the grid for this panel
51310 * @return {Roo.grid.Grid}
51312 getGrid : function(){
51316 setSize : function(width, height){
51317 if(!this.ignoreResize(width, height)){
51318 var grid = this.grid;
51319 var size = this.adjustForComponents(width, height);
51320 grid.getGridEl().setSize(size.width, size.height);
51325 beforeSlide : function(){
51326 this.grid.getView().scroller.clip();
51329 afterSlide : function(){
51330 this.grid.getView().scroller.unclip();
51333 destroy : function(){
51334 this.grid.destroy();
51336 Roo.GridPanel.superclass.destroy.call(this);
51342 * @class Roo.NestedLayoutPanel
51343 * @extends Roo.ContentPanel
51345 * Create a new NestedLayoutPanel.
51348 * @param {Roo.BorderLayout} layout The layout for this panel
51349 * @param {String/Object} config A string to set only the title or a config object
51351 Roo.NestedLayoutPanel = function(layout, config)
51353 // construct with only one argument..
51354 /* FIXME - implement nicer consturctors
51355 if (layout.layout) {
51357 layout = config.layout;
51358 delete config.layout;
51360 if (layout.xtype && !layout.getEl) {
51361 // then layout needs constructing..
51362 layout = Roo.factory(layout, Roo);
51367 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51369 layout.monitorWindowResize = false; // turn off autosizing
51370 this.layout = layout;
51371 this.layout.getEl().addClass("x-layout-nested-layout");
51378 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51380 setSize : function(width, height){
51381 if(!this.ignoreResize(width, height)){
51382 var size = this.adjustForComponents(width, height);
51383 var el = this.layout.getEl();
51384 el.setSize(size.width, size.height);
51385 var touch = el.dom.offsetWidth;
51386 this.layout.layout();
51387 // ie requires a double layout on the first pass
51388 if(Roo.isIE && !this.initialized){
51389 this.initialized = true;
51390 this.layout.layout();
51395 // activate all subpanels if not currently active..
51397 setActiveState : function(active){
51398 this.active = active;
51400 this.fireEvent("deactivate", this);
51404 this.fireEvent("activate", this);
51405 // not sure if this should happen before or after..
51406 if (!this.layout) {
51407 return; // should not happen..
51410 for (var r in this.layout.regions) {
51411 reg = this.layout.getRegion(r);
51412 if (reg.getActivePanel()) {
51413 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51414 reg.setActivePanel(reg.getActivePanel());
51417 if (!reg.panels.length) {
51420 reg.showPanel(reg.getPanel(0));
51429 * Returns the nested BorderLayout for this panel
51430 * @return {Roo.BorderLayout}
51432 getLayout : function(){
51433 return this.layout;
51437 * Adds a xtype elements to the layout of the nested panel
51441 xtype : 'ContentPanel',
51448 xtype : 'NestedLayoutPanel',
51454 items : [ ... list of content panels or nested layout panels.. ]
51458 * @param {Object} cfg Xtype definition of item to add.
51460 addxtype : function(cfg) {
51461 return this.layout.addxtype(cfg);
51466 Roo.ScrollPanel = function(el, config, content){
51467 config = config || {};
51468 config.fitToFrame = true;
51469 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
51471 this.el.dom.style.overflow = "hidden";
51472 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
51473 this.el.removeClass("x-layout-inactive-content");
51474 this.el.on("mousewheel", this.onWheel, this);
51476 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
51477 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
51478 up.unselectable(); down.unselectable();
51479 up.on("click", this.scrollUp, this);
51480 down.on("click", this.scrollDown, this);
51481 up.addClassOnOver("x-scroller-btn-over");
51482 down.addClassOnOver("x-scroller-btn-over");
51483 up.addClassOnClick("x-scroller-btn-click");
51484 down.addClassOnClick("x-scroller-btn-click");
51485 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
51487 this.resizeEl = this.el;
51488 this.el = wrap; this.up = up; this.down = down;
51491 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
51493 wheelIncrement : 5,
51494 scrollUp : function(){
51495 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
51498 scrollDown : function(){
51499 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
51502 afterScroll : function(){
51503 var el = this.resizeEl;
51504 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
51505 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51506 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51509 setSize : function(){
51510 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
51511 this.afterScroll();
51514 onWheel : function(e){
51515 var d = e.getWheelDelta();
51516 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
51517 this.afterScroll();
51521 setContent : function(content, loadScripts){
51522 this.resizeEl.update(content, loadScripts);
51536 * @class Roo.TreePanel
51537 * @extends Roo.ContentPanel
51539 * Create a new TreePanel. - defaults to fit/scoll contents.
51540 * @param {String/Object} config A string to set only the panel's title, or a config object
51541 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
51543 Roo.TreePanel = function(config){
51544 var el = config.el;
51545 var tree = config.tree;
51546 delete config.tree;
51547 delete config.el; // hopefull!
51549 // wrapper for IE7 strict & safari scroll issue
51551 var treeEl = el.createChild();
51552 config.resizeEl = treeEl;
51556 Roo.TreePanel.superclass.constructor.call(this, el, config);
51559 this.tree = new Roo.tree.TreePanel(treeEl , tree);
51560 //console.log(tree);
51561 this.on('activate', function()
51563 if (this.tree.rendered) {
51566 //console.log('render tree');
51567 this.tree.render();
51569 // this should not be needed.. - it's actually the 'el' that resizes?
51570 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
51572 //this.on('resize', function (cp, w, h) {
51573 // this.tree.innerCt.setWidth(w);
51574 // this.tree.innerCt.setHeight(h);
51575 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
51582 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
51599 * Ext JS Library 1.1.1
51600 * Copyright(c) 2006-2007, Ext JS, LLC.
51602 * Originally Released Under LGPL - original licence link has changed is not relivant.
51605 * <script type="text/javascript">
51610 * @class Roo.ReaderLayout
51611 * @extends Roo.BorderLayout
51612 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
51613 * center region containing two nested regions (a top one for a list view and one for item preview below),
51614 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
51615 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
51616 * expedites the setup of the overall layout and regions for this common application style.
51619 var reader = new Roo.ReaderLayout();
51620 var CP = Roo.ContentPanel; // shortcut for adding
51622 reader.beginUpdate();
51623 reader.add("north", new CP("north", "North"));
51624 reader.add("west", new CP("west", {title: "West"}));
51625 reader.add("east", new CP("east", {title: "East"}));
51627 reader.regions.listView.add(new CP("listView", "List"));
51628 reader.regions.preview.add(new CP("preview", "Preview"));
51629 reader.endUpdate();
51632 * Create a new ReaderLayout
51633 * @param {Object} config Configuration options
51634 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
51635 * document.body if omitted)
51637 Roo.ReaderLayout = function(config, renderTo){
51638 var c = config || {size:{}};
51639 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
51640 north: c.north !== false ? Roo.apply({
51644 }, c.north) : false,
51645 west: c.west !== false ? Roo.apply({
51653 margins:{left:5,right:0,bottom:5,top:5},
51654 cmargins:{left:5,right:5,bottom:5,top:5}
51655 }, c.west) : false,
51656 east: c.east !== false ? Roo.apply({
51664 margins:{left:0,right:5,bottom:5,top:5},
51665 cmargins:{left:5,right:5,bottom:5,top:5}
51666 }, c.east) : false,
51667 center: Roo.apply({
51668 tabPosition: 'top',
51672 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
51676 this.el.addClass('x-reader');
51678 this.beginUpdate();
51680 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
51681 south: c.preview !== false ? Roo.apply({
51688 cmargins:{top:5,left:0, right:0, bottom:0}
51689 }, c.preview) : false,
51690 center: Roo.apply({
51696 this.add('center', new Roo.NestedLayoutPanel(inner,
51697 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
51701 this.regions.preview = inner.getRegion('south');
51702 this.regions.listView = inner.getRegion('center');
51705 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
51707 * Ext JS Library 1.1.1
51708 * Copyright(c) 2006-2007, Ext JS, LLC.
51710 * Originally Released Under LGPL - original licence link has changed is not relivant.
51713 * <script type="text/javascript">
51717 * @class Roo.grid.Grid
51718 * @extends Roo.util.Observable
51719 * This class represents the primary interface of a component based grid control.
51720 * <br><br>Usage:<pre><code>
51721 var grid = new Roo.grid.Grid("my-container-id", {
51724 selModel: mySelectionModel,
51725 autoSizeColumns: true,
51726 monitorWindowResize: false,
51727 trackMouseOver: true
51732 * <b>Common Problems:</b><br/>
51733 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
51734 * element will correct this<br/>
51735 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
51736 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
51737 * are unpredictable.<br/>
51738 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
51739 * grid to calculate dimensions/offsets.<br/>
51741 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51742 * The container MUST have some type of size defined for the grid to fill. The container will be
51743 * automatically set to position relative if it isn't already.
51744 * @param {Object} config A config object that sets properties on this grid.
51746 Roo.grid.Grid = function(container, config){
51747 // initialize the container
51748 this.container = Roo.get(container);
51749 this.container.update("");
51750 this.container.setStyle("overflow", "hidden");
51751 this.container.addClass('x-grid-container');
51753 this.id = this.container.id;
51755 Roo.apply(this, config);
51756 // check and correct shorthanded configs
51758 this.dataSource = this.ds;
51762 this.colModel = this.cm;
51766 this.selModel = this.sm;
51770 if (this.selModel) {
51771 this.selModel = Roo.factory(this.selModel, Roo.grid);
51772 this.sm = this.selModel;
51773 this.sm.xmodule = this.xmodule || false;
51775 if (typeof(this.colModel.config) == 'undefined') {
51776 this.colModel = new Roo.grid.ColumnModel(this.colModel);
51777 this.cm = this.colModel;
51778 this.cm.xmodule = this.xmodule || false;
51780 if (this.dataSource) {
51781 this.dataSource= Roo.factory(this.dataSource, Roo.data);
51782 this.ds = this.dataSource;
51783 this.ds.xmodule = this.xmodule || false;
51790 this.container.setWidth(this.width);
51794 this.container.setHeight(this.height);
51801 * The raw click event for the entire grid.
51802 * @param {Roo.EventObject} e
51807 * The raw dblclick event for the entire grid.
51808 * @param {Roo.EventObject} e
51812 * @event contextmenu
51813 * The raw contextmenu event for the entire grid.
51814 * @param {Roo.EventObject} e
51816 "contextmenu" : true,
51819 * The raw mousedown event for the entire grid.
51820 * @param {Roo.EventObject} e
51822 "mousedown" : true,
51825 * The raw mouseup event for the entire grid.
51826 * @param {Roo.EventObject} e
51831 * The raw mouseover event for the entire grid.
51832 * @param {Roo.EventObject} e
51834 "mouseover" : true,
51837 * The raw mouseout event for the entire grid.
51838 * @param {Roo.EventObject} e
51843 * The raw keypress event for the entire grid.
51844 * @param {Roo.EventObject} e
51849 * The raw keydown event for the entire grid.
51850 * @param {Roo.EventObject} e
51858 * Fires when a cell is clicked
51859 * @param {Grid} this
51860 * @param {Number} rowIndex
51861 * @param {Number} columnIndex
51862 * @param {Roo.EventObject} e
51864 "cellclick" : true,
51866 * @event celldblclick
51867 * Fires when a cell is double clicked
51868 * @param {Grid} this
51869 * @param {Number} rowIndex
51870 * @param {Number} columnIndex
51871 * @param {Roo.EventObject} e
51873 "celldblclick" : true,
51876 * Fires when a row is clicked
51877 * @param {Grid} this
51878 * @param {Number} rowIndex
51879 * @param {Roo.EventObject} e
51883 * @event rowdblclick
51884 * Fires when a row is double clicked
51885 * @param {Grid} this
51886 * @param {Number} rowIndex
51887 * @param {Roo.EventObject} e
51889 "rowdblclick" : true,
51891 * @event headerclick
51892 * Fires when a header is clicked
51893 * @param {Grid} this
51894 * @param {Number} columnIndex
51895 * @param {Roo.EventObject} e
51897 "headerclick" : true,
51899 * @event headerdblclick
51900 * Fires when a header cell is double clicked
51901 * @param {Grid} this
51902 * @param {Number} columnIndex
51903 * @param {Roo.EventObject} e
51905 "headerdblclick" : true,
51907 * @event rowcontextmenu
51908 * Fires when a row is right clicked
51909 * @param {Grid} this
51910 * @param {Number} rowIndex
51911 * @param {Roo.EventObject} e
51913 "rowcontextmenu" : true,
51915 * @event cellcontextmenu
51916 * Fires when a cell is right clicked
51917 * @param {Grid} this
51918 * @param {Number} rowIndex
51919 * @param {Number} cellIndex
51920 * @param {Roo.EventObject} e
51922 "cellcontextmenu" : true,
51924 * @event headercontextmenu
51925 * Fires when a header is right clicked
51926 * @param {Grid} this
51927 * @param {Number} columnIndex
51928 * @param {Roo.EventObject} e
51930 "headercontextmenu" : true,
51932 * @event bodyscroll
51933 * Fires when the body element is scrolled
51934 * @param {Number} scrollLeft
51935 * @param {Number} scrollTop
51937 "bodyscroll" : true,
51939 * @event columnresize
51940 * Fires when the user resizes a column
51941 * @param {Number} columnIndex
51942 * @param {Number} newSize
51944 "columnresize" : true,
51946 * @event columnmove
51947 * Fires when the user moves a column
51948 * @param {Number} oldIndex
51949 * @param {Number} newIndex
51951 "columnmove" : true,
51954 * Fires when row(s) start being dragged
51955 * @param {Grid} this
51956 * @param {Roo.GridDD} dd The drag drop object
51957 * @param {event} e The raw browser event
51959 "startdrag" : true,
51962 * Fires when a drag operation is complete
51963 * @param {Grid} this
51964 * @param {Roo.GridDD} dd The drag drop object
51965 * @param {event} e The raw browser event
51970 * Fires when dragged row(s) are dropped on a valid DD target
51971 * @param {Grid} this
51972 * @param {Roo.GridDD} dd The drag drop object
51973 * @param {String} targetId The target drag drop object
51974 * @param {event} e The raw browser event
51979 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
51980 * @param {Grid} this
51981 * @param {Roo.GridDD} dd The drag drop object
51982 * @param {String} targetId The target drag drop object
51983 * @param {event} e The raw browser event
51988 * Fires when the dragged row(s) first cross another DD target while being dragged
51989 * @param {Grid} this
51990 * @param {Roo.GridDD} dd The drag drop object
51991 * @param {String} targetId The target drag drop object
51992 * @param {event} e The raw browser event
51994 "dragenter" : true,
51997 * Fires when the dragged row(s) leave another DD target while being dragged
51998 * @param {Grid} this
51999 * @param {Roo.GridDD} dd The drag drop object
52000 * @param {String} targetId The target drag drop object
52001 * @param {event} e The raw browser event
52006 * Fires when a row is rendered, so you can change add a style to it.
52007 * @param {GridView} gridview The grid view
52008 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52014 * Fires when the grid is rendered
52015 * @param {Grid} grid
52020 Roo.grid.Grid.superclass.constructor.call(this);
52022 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52025 * @cfg {String} ddGroup - drag drop group.
52029 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52031 minColumnWidth : 25,
52034 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52035 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52036 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52038 autoSizeColumns : false,
52041 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52043 autoSizeHeaders : true,
52046 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52048 monitorWindowResize : true,
52051 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52052 * rows measured to get a columns size. Default is 0 (all rows).
52054 maxRowsToMeasure : 0,
52057 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52059 trackMouseOver : true,
52062 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52066 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52068 enableDragDrop : false,
52071 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52073 enableColumnMove : true,
52076 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52078 enableColumnHide : true,
52081 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52083 enableRowHeightSync : false,
52086 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52091 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52093 autoHeight : false,
52096 * @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.
52098 autoExpandColumn : false,
52101 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52104 autoExpandMin : 50,
52107 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52109 autoExpandMax : 1000,
52112 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52117 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52121 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52131 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52132 * of a fixed width. Default is false.
52135 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52138 * Called once after all setup has been completed and the grid is ready to be rendered.
52139 * @return {Roo.grid.Grid} this
52141 render : function()
52143 var c = this.container;
52144 // try to detect autoHeight/width mode
52145 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52146 this.autoHeight = true;
52148 var view = this.getView();
52151 c.on("click", this.onClick, this);
52152 c.on("dblclick", this.onDblClick, this);
52153 c.on("contextmenu", this.onContextMenu, this);
52154 c.on("keydown", this.onKeyDown, this);
52156 c.on("touchstart", this.onTouchStart, this);
52159 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52161 this.getSelectionModel().init(this);
52166 this.loadMask = new Roo.LoadMask(this.container,
52167 Roo.apply({store:this.dataSource}, this.loadMask));
52171 if (this.toolbar && this.toolbar.xtype) {
52172 this.toolbar.container = this.getView().getHeaderPanel(true);
52173 this.toolbar = new Roo.Toolbar(this.toolbar);
52175 if (this.footer && this.footer.xtype) {
52176 this.footer.dataSource = this.getDataSource();
52177 this.footer.container = this.getView().getFooterPanel(true);
52178 this.footer = Roo.factory(this.footer, Roo);
52180 if (this.dropTarget && this.dropTarget.xtype) {
52181 delete this.dropTarget.xtype;
52182 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52186 this.rendered = true;
52187 this.fireEvent('render', this);
52192 * Reconfigures the grid to use a different Store and Column Model.
52193 * The View will be bound to the new objects and refreshed.
52194 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52195 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52197 reconfigure : function(dataSource, colModel){
52199 this.loadMask.destroy();
52200 this.loadMask = new Roo.LoadMask(this.container,
52201 Roo.apply({store:dataSource}, this.loadMask));
52203 this.view.bind(dataSource, colModel);
52204 this.dataSource = dataSource;
52205 this.colModel = colModel;
52206 this.view.refresh(true);
52210 onKeyDown : function(e){
52211 this.fireEvent("keydown", e);
52215 * Destroy this grid.
52216 * @param {Boolean} removeEl True to remove the element
52218 destroy : function(removeEl, keepListeners){
52220 this.loadMask.destroy();
52222 var c = this.container;
52223 c.removeAllListeners();
52224 this.view.destroy();
52225 this.colModel.purgeListeners();
52226 if(!keepListeners){
52227 this.purgeListeners();
52230 if(removeEl === true){
52236 processEvent : function(name, e){
52237 // does this fire select???
52238 Roo.log('grid:processEvent ' + name);
52240 if (name != 'touchstart' ) {
52241 this.fireEvent(name, e);
52244 var t = e.getTarget();
52246 var header = v.findHeaderIndex(t);
52247 if(header !== false){
52248 var ename = name == 'touchstart' ? 'click' : name;
52250 this.fireEvent("header" + ename, this, header, e);
52252 var row = v.findRowIndex(t);
52253 var cell = v.findCellIndex(t);
52254 if (name == 'touchstart') {
52255 // first touch is always a click.
52256 // hopefull this happens after selection is updated.?
52259 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52260 var cs = this.selModel.getSelectedCell();
52261 if (row == cs[0] && cell == cs[1]){
52265 if (typeof(this.selModel.getSelections) != 'undefined') {
52266 var cs = this.selModel.getSelections();
52267 var ds = this.dataSource;
52268 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52279 this.fireEvent("row" + name, this, row, e);
52280 if(cell !== false){
52281 this.fireEvent("cell" + name, this, row, cell, e);
52288 onClick : function(e){
52289 this.processEvent("click", e);
52292 onTouchStart : function(e){
52293 this.processEvent("touchstart", e);
52297 onContextMenu : function(e, t){
52298 this.processEvent("contextmenu", e);
52302 onDblClick : function(e){
52303 this.processEvent("dblclick", e);
52307 walkCells : function(row, col, step, fn, scope){
52308 var cm = this.colModel, clen = cm.getColumnCount();
52309 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52321 if(fn.call(scope || this, row, col, cm) === true){
52339 if(fn.call(scope || this, row, col, cm) === true){
52351 getSelections : function(){
52352 return this.selModel.getSelections();
52356 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52357 * but if manual update is required this method will initiate it.
52359 autoSize : function(){
52361 this.view.layout();
52362 if(this.view.adjustForScroll){
52363 this.view.adjustForScroll();
52369 * Returns the grid's underlying element.
52370 * @return {Element} The element
52372 getGridEl : function(){
52373 return this.container;
52376 // private for compatibility, overridden by editor grid
52377 stopEditing : function(){},
52380 * Returns the grid's SelectionModel.
52381 * @return {SelectionModel}
52383 getSelectionModel : function(){
52384 if(!this.selModel){
52385 this.selModel = new Roo.grid.RowSelectionModel();
52387 return this.selModel;
52391 * Returns the grid's DataSource.
52392 * @return {DataSource}
52394 getDataSource : function(){
52395 return this.dataSource;
52399 * Returns the grid's ColumnModel.
52400 * @return {ColumnModel}
52402 getColumnModel : function(){
52403 return this.colModel;
52407 * Returns the grid's GridView object.
52408 * @return {GridView}
52410 getView : function(){
52412 this.view = new Roo.grid.GridView(this.viewConfig);
52417 * Called to get grid's drag proxy text, by default returns this.ddText.
52420 getDragDropText : function(){
52421 var count = this.selModel.getCount();
52422 return String.format(this.ddText, count, count == 1 ? '' : 's');
52426 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
52427 * %0 is replaced with the number of selected rows.
52430 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
52432 * Ext JS Library 1.1.1
52433 * Copyright(c) 2006-2007, Ext JS, LLC.
52435 * Originally Released Under LGPL - original licence link has changed is not relivant.
52438 * <script type="text/javascript">
52441 Roo.grid.AbstractGridView = function(){
52445 "beforerowremoved" : true,
52446 "beforerowsinserted" : true,
52447 "beforerefresh" : true,
52448 "rowremoved" : true,
52449 "rowsinserted" : true,
52450 "rowupdated" : true,
52453 Roo.grid.AbstractGridView.superclass.constructor.call(this);
52456 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
52457 rowClass : "x-grid-row",
52458 cellClass : "x-grid-cell",
52459 tdClass : "x-grid-td",
52460 hdClass : "x-grid-hd",
52461 splitClass : "x-grid-hd-split",
52463 init: function(grid){
52465 var cid = this.grid.getGridEl().id;
52466 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
52467 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
52468 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
52469 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
52472 getColumnRenderers : function(){
52473 var renderers = [];
52474 var cm = this.grid.colModel;
52475 var colCount = cm.getColumnCount();
52476 for(var i = 0; i < colCount; i++){
52477 renderers[i] = cm.getRenderer(i);
52482 getColumnIds : function(){
52484 var cm = this.grid.colModel;
52485 var colCount = cm.getColumnCount();
52486 for(var i = 0; i < colCount; i++){
52487 ids[i] = cm.getColumnId(i);
52492 getDataIndexes : function(){
52493 if(!this.indexMap){
52494 this.indexMap = this.buildIndexMap();
52496 return this.indexMap.colToData;
52499 getColumnIndexByDataIndex : function(dataIndex){
52500 if(!this.indexMap){
52501 this.indexMap = this.buildIndexMap();
52503 return this.indexMap.dataToCol[dataIndex];
52507 * Set a css style for a column dynamically.
52508 * @param {Number} colIndex The index of the column
52509 * @param {String} name The css property name
52510 * @param {String} value The css value
52512 setCSSStyle : function(colIndex, name, value){
52513 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
52514 Roo.util.CSS.updateRule(selector, name, value);
52517 generateRules : function(cm){
52518 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
52519 Roo.util.CSS.removeStyleSheet(rulesId);
52520 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52521 var cid = cm.getColumnId(i);
52522 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
52523 this.tdSelector, cid, " {\n}\n",
52524 this.hdSelector, cid, " {\n}\n",
52525 this.splitSelector, cid, " {\n}\n");
52527 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52531 * Ext JS Library 1.1.1
52532 * Copyright(c) 2006-2007, Ext JS, LLC.
52534 * Originally Released Under LGPL - original licence link has changed is not relivant.
52537 * <script type="text/javascript">
52541 // This is a support class used internally by the Grid components
52542 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
52544 this.view = grid.getView();
52545 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52546 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
52548 this.setHandleElId(Roo.id(hd));
52549 this.setOuterHandleElId(Roo.id(hd2));
52551 this.scroll = false;
52553 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
52555 getDragData : function(e){
52556 var t = Roo.lib.Event.getTarget(e);
52557 var h = this.view.findHeaderCell(t);
52559 return {ddel: h.firstChild, header:h};
52564 onInitDrag : function(e){
52565 this.view.headersDisabled = true;
52566 var clone = this.dragData.ddel.cloneNode(true);
52567 clone.id = Roo.id();
52568 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
52569 this.proxy.update(clone);
52573 afterValidDrop : function(){
52575 setTimeout(function(){
52576 v.headersDisabled = false;
52580 afterInvalidDrop : function(){
52582 setTimeout(function(){
52583 v.headersDisabled = false;
52589 * Ext JS Library 1.1.1
52590 * Copyright(c) 2006-2007, Ext JS, LLC.
52592 * Originally Released Under LGPL - original licence link has changed is not relivant.
52595 * <script type="text/javascript">
52598 // This is a support class used internally by the Grid components
52599 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
52601 this.view = grid.getView();
52602 // split the proxies so they don't interfere with mouse events
52603 this.proxyTop = Roo.DomHelper.append(document.body, {
52604 cls:"col-move-top", html:" "
52606 this.proxyBottom = Roo.DomHelper.append(document.body, {
52607 cls:"col-move-bottom", html:" "
52609 this.proxyTop.hide = this.proxyBottom.hide = function(){
52610 this.setLeftTop(-100,-100);
52611 this.setStyle("visibility", "hidden");
52613 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52614 // temporarily disabled
52615 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
52616 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
52618 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
52619 proxyOffsets : [-4, -9],
52620 fly: Roo.Element.fly,
52622 getTargetFromEvent : function(e){
52623 var t = Roo.lib.Event.getTarget(e);
52624 var cindex = this.view.findCellIndex(t);
52625 if(cindex !== false){
52626 return this.view.getHeaderCell(cindex);
52631 nextVisible : function(h){
52632 var v = this.view, cm = this.grid.colModel;
52635 if(!cm.isHidden(v.getCellIndex(h))){
52643 prevVisible : function(h){
52644 var v = this.view, cm = this.grid.colModel;
52647 if(!cm.isHidden(v.getCellIndex(h))){
52655 positionIndicator : function(h, n, e){
52656 var x = Roo.lib.Event.getPageX(e);
52657 var r = Roo.lib.Dom.getRegion(n.firstChild);
52658 var px, pt, py = r.top + this.proxyOffsets[1];
52659 if((r.right - x) <= (r.right-r.left)/2){
52660 px = r.right+this.view.borderWidth;
52666 var oldIndex = this.view.getCellIndex(h);
52667 var newIndex = this.view.getCellIndex(n);
52669 if(this.grid.colModel.isFixed(newIndex)){
52673 var locked = this.grid.colModel.isLocked(newIndex);
52678 if(oldIndex < newIndex){
52681 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
52684 px += this.proxyOffsets[0];
52685 this.proxyTop.setLeftTop(px, py);
52686 this.proxyTop.show();
52687 if(!this.bottomOffset){
52688 this.bottomOffset = this.view.mainHd.getHeight();
52690 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
52691 this.proxyBottom.show();
52695 onNodeEnter : function(n, dd, e, data){
52696 if(data.header != n){
52697 this.positionIndicator(data.header, n, e);
52701 onNodeOver : function(n, dd, e, data){
52702 var result = false;
52703 if(data.header != n){
52704 result = this.positionIndicator(data.header, n, e);
52707 this.proxyTop.hide();
52708 this.proxyBottom.hide();
52710 return result ? this.dropAllowed : this.dropNotAllowed;
52713 onNodeOut : function(n, dd, e, data){
52714 this.proxyTop.hide();
52715 this.proxyBottom.hide();
52718 onNodeDrop : function(n, dd, e, data){
52719 var h = data.header;
52721 var cm = this.grid.colModel;
52722 var x = Roo.lib.Event.getPageX(e);
52723 var r = Roo.lib.Dom.getRegion(n.firstChild);
52724 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
52725 var oldIndex = this.view.getCellIndex(h);
52726 var newIndex = this.view.getCellIndex(n);
52727 var locked = cm.isLocked(newIndex);
52731 if(oldIndex < newIndex){
52734 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
52737 cm.setLocked(oldIndex, locked, true);
52738 cm.moveColumn(oldIndex, newIndex);
52739 this.grid.fireEvent("columnmove", oldIndex, newIndex);
52747 * Ext JS Library 1.1.1
52748 * Copyright(c) 2006-2007, Ext JS, LLC.
52750 * Originally Released Under LGPL - original licence link has changed is not relivant.
52753 * <script type="text/javascript">
52757 * @class Roo.grid.GridView
52758 * @extends Roo.util.Observable
52761 * @param {Object} config
52763 Roo.grid.GridView = function(config){
52764 Roo.grid.GridView.superclass.constructor.call(this);
52767 Roo.apply(this, config);
52770 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
52772 unselectable : 'unselectable="on"',
52773 unselectableCls : 'x-unselectable',
52776 rowClass : "x-grid-row",
52778 cellClass : "x-grid-col",
52780 tdClass : "x-grid-td",
52782 hdClass : "x-grid-hd",
52784 splitClass : "x-grid-split",
52786 sortClasses : ["sort-asc", "sort-desc"],
52788 enableMoveAnim : false,
52792 dh : Roo.DomHelper,
52794 fly : Roo.Element.fly,
52796 css : Roo.util.CSS,
52802 scrollIncrement : 22,
52804 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
52806 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
52808 bind : function(ds, cm){
52810 this.ds.un("load", this.onLoad, this);
52811 this.ds.un("datachanged", this.onDataChange, this);
52812 this.ds.un("add", this.onAdd, this);
52813 this.ds.un("remove", this.onRemove, this);
52814 this.ds.un("update", this.onUpdate, this);
52815 this.ds.un("clear", this.onClear, this);
52818 ds.on("load", this.onLoad, this);
52819 ds.on("datachanged", this.onDataChange, this);
52820 ds.on("add", this.onAdd, this);
52821 ds.on("remove", this.onRemove, this);
52822 ds.on("update", this.onUpdate, this);
52823 ds.on("clear", this.onClear, this);
52828 this.cm.un("widthchange", this.onColWidthChange, this);
52829 this.cm.un("headerchange", this.onHeaderChange, this);
52830 this.cm.un("hiddenchange", this.onHiddenChange, this);
52831 this.cm.un("columnmoved", this.onColumnMove, this);
52832 this.cm.un("columnlockchange", this.onColumnLock, this);
52835 this.generateRules(cm);
52836 cm.on("widthchange", this.onColWidthChange, this);
52837 cm.on("headerchange", this.onHeaderChange, this);
52838 cm.on("hiddenchange", this.onHiddenChange, this);
52839 cm.on("columnmoved", this.onColumnMove, this);
52840 cm.on("columnlockchange", this.onColumnLock, this);
52845 init: function(grid){
52846 Roo.grid.GridView.superclass.init.call(this, grid);
52848 this.bind(grid.dataSource, grid.colModel);
52850 grid.on("headerclick", this.handleHeaderClick, this);
52852 if(grid.trackMouseOver){
52853 grid.on("mouseover", this.onRowOver, this);
52854 grid.on("mouseout", this.onRowOut, this);
52856 grid.cancelTextSelection = function(){};
52857 this.gridId = grid.id;
52859 var tpls = this.templates || {};
52862 tpls.master = new Roo.Template(
52863 '<div class="x-grid" hidefocus="true">',
52864 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
52865 '<div class="x-grid-topbar"></div>',
52866 '<div class="x-grid-scroller"><div></div></div>',
52867 '<div class="x-grid-locked">',
52868 '<div class="x-grid-header">{lockedHeader}</div>',
52869 '<div class="x-grid-body">{lockedBody}</div>',
52871 '<div class="x-grid-viewport">',
52872 '<div class="x-grid-header">{header}</div>',
52873 '<div class="x-grid-body">{body}</div>',
52875 '<div class="x-grid-bottombar"></div>',
52877 '<div class="x-grid-resize-proxy"> </div>',
52880 tpls.master.disableformats = true;
52884 tpls.header = new Roo.Template(
52885 '<table border="0" cellspacing="0" cellpadding="0">',
52886 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
52889 tpls.header.disableformats = true;
52891 tpls.header.compile();
52894 tpls.hcell = new Roo.Template(
52895 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
52896 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
52899 tpls.hcell.disableFormats = true;
52901 tpls.hcell.compile();
52904 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
52905 this.unselectableCls + '" ' + this.unselectable +'> </div>');
52906 tpls.hsplit.disableFormats = true;
52908 tpls.hsplit.compile();
52911 tpls.body = new Roo.Template(
52912 '<table border="0" cellspacing="0" cellpadding="0">',
52913 "<tbody>{rows}</tbody>",
52916 tpls.body.disableFormats = true;
52918 tpls.body.compile();
52921 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
52922 tpls.row.disableFormats = true;
52924 tpls.row.compile();
52927 tpls.cell = new Roo.Template(
52928 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
52929 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
52930 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
52933 tpls.cell.disableFormats = true;
52935 tpls.cell.compile();
52937 this.templates = tpls;
52940 // remap these for backwards compat
52941 onColWidthChange : function(){
52942 this.updateColumns.apply(this, arguments);
52944 onHeaderChange : function(){
52945 this.updateHeaders.apply(this, arguments);
52947 onHiddenChange : function(){
52948 this.handleHiddenChange.apply(this, arguments);
52950 onColumnMove : function(){
52951 this.handleColumnMove.apply(this, arguments);
52953 onColumnLock : function(){
52954 this.handleLockChange.apply(this, arguments);
52957 onDataChange : function(){
52959 this.updateHeaderSortState();
52962 onClear : function(){
52966 onUpdate : function(ds, record){
52967 this.refreshRow(record);
52970 refreshRow : function(record){
52971 var ds = this.ds, index;
52972 if(typeof record == 'number'){
52974 record = ds.getAt(index);
52976 index = ds.indexOf(record);
52978 this.insertRows(ds, index, index, true);
52979 this.onRemove(ds, record, index+1, true);
52980 this.syncRowHeights(index, index);
52982 this.fireEvent("rowupdated", this, index, record);
52985 onAdd : function(ds, records, index){
52986 this.insertRows(ds, index, index + (records.length-1));
52989 onRemove : function(ds, record, index, isUpdate){
52990 if(isUpdate !== true){
52991 this.fireEvent("beforerowremoved", this, index, record);
52993 var bt = this.getBodyTable(), lt = this.getLockedTable();
52994 if(bt.rows[index]){
52995 bt.firstChild.removeChild(bt.rows[index]);
52997 if(lt.rows[index]){
52998 lt.firstChild.removeChild(lt.rows[index]);
53000 if(isUpdate !== true){
53001 this.stripeRows(index);
53002 this.syncRowHeights(index, index);
53004 this.fireEvent("rowremoved", this, index, record);
53008 onLoad : function(){
53009 this.scrollToTop();
53013 * Scrolls the grid to the top
53015 scrollToTop : function(){
53017 this.scroller.dom.scrollTop = 0;
53023 * Gets a panel in the header of the grid that can be used for toolbars etc.
53024 * After modifying the contents of this panel a call to grid.autoSize() may be
53025 * required to register any changes in size.
53026 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53027 * @return Roo.Element
53029 getHeaderPanel : function(doShow){
53031 this.headerPanel.show();
53033 return this.headerPanel;
53037 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53038 * After modifying the contents of this panel a call to grid.autoSize() may be
53039 * required to register any changes in size.
53040 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53041 * @return Roo.Element
53043 getFooterPanel : function(doShow){
53045 this.footerPanel.show();
53047 return this.footerPanel;
53050 initElements : function(){
53051 var E = Roo.Element;
53052 var el = this.grid.getGridEl().dom.firstChild;
53053 var cs = el.childNodes;
53055 this.el = new E(el);
53057 this.focusEl = new E(el.firstChild);
53058 this.focusEl.swallowEvent("click", true);
53060 this.headerPanel = new E(cs[1]);
53061 this.headerPanel.enableDisplayMode("block");
53063 this.scroller = new E(cs[2]);
53064 this.scrollSizer = new E(this.scroller.dom.firstChild);
53066 this.lockedWrap = new E(cs[3]);
53067 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53068 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53070 this.mainWrap = new E(cs[4]);
53071 this.mainHd = new E(this.mainWrap.dom.firstChild);
53072 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53074 this.footerPanel = new E(cs[5]);
53075 this.footerPanel.enableDisplayMode("block");
53077 this.resizeProxy = new E(cs[6]);
53079 this.headerSelector = String.format(
53080 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53081 this.lockedHd.id, this.mainHd.id
53084 this.splitterSelector = String.format(
53085 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53086 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53089 idToCssName : function(s)
53091 return s.replace(/[^a-z0-9]+/ig, '-');
53094 getHeaderCell : function(index){
53095 return Roo.DomQuery.select(this.headerSelector)[index];
53098 getHeaderCellMeasure : function(index){
53099 return this.getHeaderCell(index).firstChild;
53102 getHeaderCellText : function(index){
53103 return this.getHeaderCell(index).firstChild.firstChild;
53106 getLockedTable : function(){
53107 return this.lockedBody.dom.firstChild;
53110 getBodyTable : function(){
53111 return this.mainBody.dom.firstChild;
53114 getLockedRow : function(index){
53115 return this.getLockedTable().rows[index];
53118 getRow : function(index){
53119 return this.getBodyTable().rows[index];
53122 getRowComposite : function(index){
53124 this.rowEl = new Roo.CompositeElementLite();
53126 var els = [], lrow, mrow;
53127 if(lrow = this.getLockedRow(index)){
53130 if(mrow = this.getRow(index)){
53133 this.rowEl.elements = els;
53137 * Gets the 'td' of the cell
53139 * @param {Integer} rowIndex row to select
53140 * @param {Integer} colIndex column to select
53144 getCell : function(rowIndex, colIndex){
53145 var locked = this.cm.getLockedCount();
53147 if(colIndex < locked){
53148 source = this.lockedBody.dom.firstChild;
53150 source = this.mainBody.dom.firstChild;
53151 colIndex -= locked;
53153 return source.rows[rowIndex].childNodes[colIndex];
53156 getCellText : function(rowIndex, colIndex){
53157 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53160 getCellBox : function(cell){
53161 var b = this.fly(cell).getBox();
53162 if(Roo.isOpera){ // opera fails to report the Y
53163 b.y = cell.offsetTop + this.mainBody.getY();
53168 getCellIndex : function(cell){
53169 var id = String(cell.className).match(this.cellRE);
53171 return parseInt(id[1], 10);
53176 findHeaderIndex : function(n){
53177 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53178 return r ? this.getCellIndex(r) : false;
53181 findHeaderCell : function(n){
53182 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53183 return r ? r : false;
53186 findRowIndex : function(n){
53190 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53191 return r ? r.rowIndex : false;
53194 findCellIndex : function(node){
53195 var stop = this.el.dom;
53196 while(node && node != stop){
53197 if(this.findRE.test(node.className)){
53198 return this.getCellIndex(node);
53200 node = node.parentNode;
53205 getColumnId : function(index){
53206 return this.cm.getColumnId(index);
53209 getSplitters : function()
53211 if(this.splitterSelector){
53212 return Roo.DomQuery.select(this.splitterSelector);
53218 getSplitter : function(index){
53219 return this.getSplitters()[index];
53222 onRowOver : function(e, t){
53224 if((row = this.findRowIndex(t)) !== false){
53225 this.getRowComposite(row).addClass("x-grid-row-over");
53229 onRowOut : function(e, t){
53231 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53232 this.getRowComposite(row).removeClass("x-grid-row-over");
53236 renderHeaders : function(){
53238 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53239 var cb = [], lb = [], sb = [], lsb = [], p = {};
53240 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53241 p.cellId = "x-grid-hd-0-" + i;
53242 p.splitId = "x-grid-csplit-0-" + i;
53243 p.id = cm.getColumnId(i);
53244 p.title = cm.getColumnTooltip(i) || "";
53245 p.value = cm.getColumnHeader(i) || "";
53246 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53247 if(!cm.isLocked(i)){
53248 cb[cb.length] = ct.apply(p);
53249 sb[sb.length] = st.apply(p);
53251 lb[lb.length] = ct.apply(p);
53252 lsb[lsb.length] = st.apply(p);
53255 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53256 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53259 updateHeaders : function(){
53260 var html = this.renderHeaders();
53261 this.lockedHd.update(html[0]);
53262 this.mainHd.update(html[1]);
53266 * Focuses the specified row.
53267 * @param {Number} row The row index
53269 focusRow : function(row)
53271 //Roo.log('GridView.focusRow');
53272 var x = this.scroller.dom.scrollLeft;
53273 this.focusCell(row, 0, false);
53274 this.scroller.dom.scrollLeft = x;
53278 * Focuses the specified cell.
53279 * @param {Number} row The row index
53280 * @param {Number} col The column index
53281 * @param {Boolean} hscroll false to disable horizontal scrolling
53283 focusCell : function(row, col, hscroll)
53285 //Roo.log('GridView.focusCell');
53286 var el = this.ensureVisible(row, col, hscroll);
53287 this.focusEl.alignTo(el, "tl-tl");
53289 this.focusEl.focus();
53291 this.focusEl.focus.defer(1, this.focusEl);
53296 * Scrolls the specified cell into view
53297 * @param {Number} row The row index
53298 * @param {Number} col The column index
53299 * @param {Boolean} hscroll false to disable horizontal scrolling
53301 ensureVisible : function(row, col, hscroll)
53303 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53304 //return null; //disable for testing.
53305 if(typeof row != "number"){
53306 row = row.rowIndex;
53308 if(row < 0 && row >= this.ds.getCount()){
53311 col = (col !== undefined ? col : 0);
53312 var cm = this.grid.colModel;
53313 while(cm.isHidden(col)){
53317 var el = this.getCell(row, col);
53321 var c = this.scroller.dom;
53323 var ctop = parseInt(el.offsetTop, 10);
53324 var cleft = parseInt(el.offsetLeft, 10);
53325 var cbot = ctop + el.offsetHeight;
53326 var cright = cleft + el.offsetWidth;
53328 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53329 var stop = parseInt(c.scrollTop, 10);
53330 var sleft = parseInt(c.scrollLeft, 10);
53331 var sbot = stop + ch;
53332 var sright = sleft + c.clientWidth;
53334 Roo.log('GridView.ensureVisible:' +
53336 ' c.clientHeight:' + c.clientHeight +
53337 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53345 c.scrollTop = ctop;
53346 //Roo.log("set scrolltop to ctop DISABLE?");
53347 }else if(cbot > sbot){
53348 //Roo.log("set scrolltop to cbot-ch");
53349 c.scrollTop = cbot-ch;
53352 if(hscroll !== false){
53354 c.scrollLeft = cleft;
53355 }else if(cright > sright){
53356 c.scrollLeft = cright-c.clientWidth;
53363 updateColumns : function(){
53364 this.grid.stopEditing();
53365 var cm = this.grid.colModel, colIds = this.getColumnIds();
53366 //var totalWidth = cm.getTotalWidth();
53368 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53369 //if(cm.isHidden(i)) continue;
53370 var w = cm.getColumnWidth(i);
53371 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53372 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53374 this.updateSplitters();
53377 generateRules : function(cm){
53378 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53379 Roo.util.CSS.removeStyleSheet(rulesId);
53380 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53381 var cid = cm.getColumnId(i);
53383 if(cm.config[i].align){
53384 align = 'text-align:'+cm.config[i].align+';';
53387 if(cm.isHidden(i)){
53388 hidden = 'display:none;';
53390 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53392 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53393 this.hdSelector, cid, " {\n", align, width, "}\n",
53394 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53395 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53397 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53400 updateSplitters : function(){
53401 var cm = this.cm, s = this.getSplitters();
53402 if(s){ // splitters not created yet
53403 var pos = 0, locked = true;
53404 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53405 if(cm.isHidden(i)) continue;
53406 var w = cm.getColumnWidth(i); // make sure it's a number
53407 if(!cm.isLocked(i) && locked){
53412 s[i].style.left = (pos-this.splitOffset) + "px";
53417 handleHiddenChange : function(colModel, colIndex, hidden){
53419 this.hideColumn(colIndex);
53421 this.unhideColumn(colIndex);
53425 hideColumn : function(colIndex){
53426 var cid = this.getColumnId(colIndex);
53427 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
53428 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
53430 this.updateHeaders();
53432 this.updateSplitters();
53436 unhideColumn : function(colIndex){
53437 var cid = this.getColumnId(colIndex);
53438 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
53439 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
53442 this.updateHeaders();
53444 this.updateSplitters();
53448 insertRows : function(dm, firstRow, lastRow, isUpdate){
53449 if(firstRow == 0 && lastRow == dm.getCount()-1){
53453 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
53455 var s = this.getScrollState();
53456 var markup = this.renderRows(firstRow, lastRow);
53457 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
53458 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
53459 this.restoreScroll(s);
53461 this.fireEvent("rowsinserted", this, firstRow, lastRow);
53462 this.syncRowHeights(firstRow, lastRow);
53463 this.stripeRows(firstRow);
53469 bufferRows : function(markup, target, index){
53470 var before = null, trows = target.rows, tbody = target.tBodies[0];
53471 if(index < trows.length){
53472 before = trows[index];
53474 var b = document.createElement("div");
53475 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
53476 var rows = b.firstChild.rows;
53477 for(var i = 0, len = rows.length; i < len; i++){
53479 tbody.insertBefore(rows[0], before);
53481 tbody.appendChild(rows[0]);
53488 deleteRows : function(dm, firstRow, lastRow){
53489 if(dm.getRowCount()<1){
53490 this.fireEvent("beforerefresh", this);
53491 this.mainBody.update("");
53492 this.lockedBody.update("");
53493 this.fireEvent("refresh", this);
53495 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
53496 var bt = this.getBodyTable();
53497 var tbody = bt.firstChild;
53498 var rows = bt.rows;
53499 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
53500 tbody.removeChild(rows[firstRow]);
53502 this.stripeRows(firstRow);
53503 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
53507 updateRows : function(dataSource, firstRow, lastRow){
53508 var s = this.getScrollState();
53510 this.restoreScroll(s);
53513 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
53517 this.updateHeaderSortState();
53520 getScrollState : function(){
53522 var sb = this.scroller.dom;
53523 return {left: sb.scrollLeft, top: sb.scrollTop};
53526 stripeRows : function(startRow){
53527 if(!this.grid.stripeRows || this.ds.getCount() < 1){
53530 startRow = startRow || 0;
53531 var rows = this.getBodyTable().rows;
53532 var lrows = this.getLockedTable().rows;
53533 var cls = ' x-grid-row-alt ';
53534 for(var i = startRow, len = rows.length; i < len; i++){
53535 var row = rows[i], lrow = lrows[i];
53536 var isAlt = ((i+1) % 2 == 0);
53537 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
53538 if(isAlt == hasAlt){
53542 row.className += " x-grid-row-alt";
53544 row.className = row.className.replace("x-grid-row-alt", "");
53547 lrow.className = row.className;
53552 restoreScroll : function(state){
53553 //Roo.log('GridView.restoreScroll');
53554 var sb = this.scroller.dom;
53555 sb.scrollLeft = state.left;
53556 sb.scrollTop = state.top;
53560 syncScroll : function(){
53561 //Roo.log('GridView.syncScroll');
53562 var sb = this.scroller.dom;
53563 var sh = this.mainHd.dom;
53564 var bs = this.mainBody.dom;
53565 var lv = this.lockedBody.dom;
53566 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
53567 lv.scrollTop = bs.scrollTop = sb.scrollTop;
53570 handleScroll : function(e){
53572 var sb = this.scroller.dom;
53573 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
53577 handleWheel : function(e){
53578 var d = e.getWheelDelta();
53579 this.scroller.dom.scrollTop -= d*22;
53580 // set this here to prevent jumpy scrolling on large tables
53581 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
53585 renderRows : function(startRow, endRow){
53586 // pull in all the crap needed to render rows
53587 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
53588 var colCount = cm.getColumnCount();
53590 if(ds.getCount() < 1){
53594 // build a map for all the columns
53596 for(var i = 0; i < colCount; i++){
53597 var name = cm.getDataIndex(i);
53599 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
53600 renderer : cm.getRenderer(i),
53601 id : cm.getColumnId(i),
53602 locked : cm.isLocked(i)
53606 startRow = startRow || 0;
53607 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
53609 // records to render
53610 var rs = ds.getRange(startRow, endRow);
53612 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
53615 // As much as I hate to duplicate code, this was branched because FireFox really hates
53616 // [].join("") on strings. The performance difference was substantial enough to
53617 // branch this function
53618 doRender : Roo.isGecko ?
53619 function(cs, rs, ds, startRow, colCount, stripe){
53620 var ts = this.templates, ct = ts.cell, rt = ts.row;
53622 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53624 var hasListener = this.grid.hasListener('rowclass');
53626 for(var j = 0, len = rs.length; j < len; j++){
53627 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
53628 for(var i = 0; i < colCount; i++){
53630 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53632 p.css = p.attr = "";
53633 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53634 if(p.value == undefined || p.value === "") p.value = " ";
53635 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53636 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53638 var markup = ct.apply(p);
53646 if(stripe && ((rowIndex+1) % 2 == 0)){
53647 alt.push("x-grid-row-alt")
53650 alt.push( " x-grid-dirty-row");
53653 if(this.getRowClass){
53654 alt.push(this.getRowClass(r, rowIndex));
53660 rowIndex : rowIndex,
53663 this.grid.fireEvent('rowclass', this, rowcfg);
53664 alt.push(rowcfg.rowClass);
53666 rp.alt = alt.join(" ");
53667 lbuf+= rt.apply(rp);
53669 buf+= rt.apply(rp);
53671 return [lbuf, buf];
53673 function(cs, rs, ds, startRow, colCount, stripe){
53674 var ts = this.templates, ct = ts.cell, rt = ts.row;
53676 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53677 var hasListener = this.grid.hasListener('rowclass');
53680 for(var j = 0, len = rs.length; j < len; j++){
53681 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
53682 for(var i = 0; i < colCount; i++){
53684 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53686 p.css = p.attr = "";
53687 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53688 if(p.value == undefined || p.value === "") p.value = " ";
53689 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53690 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53693 var markup = ct.apply(p);
53695 cb[cb.length] = markup;
53697 lcb[lcb.length] = markup;
53701 if(stripe && ((rowIndex+1) % 2 == 0)){
53702 alt.push( "x-grid-row-alt");
53705 alt.push(" x-grid-dirty-row");
53708 if(this.getRowClass){
53709 alt.push( this.getRowClass(r, rowIndex));
53715 rowIndex : rowIndex,
53718 this.grid.fireEvent('rowclass', this, rowcfg);
53719 alt.push(rowcfg.rowClass);
53721 rp.alt = alt.join(" ");
53722 rp.cells = lcb.join("");
53723 lbuf[lbuf.length] = rt.apply(rp);
53724 rp.cells = cb.join("");
53725 buf[buf.length] = rt.apply(rp);
53727 return [lbuf.join(""), buf.join("")];
53730 renderBody : function(){
53731 var markup = this.renderRows();
53732 var bt = this.templates.body;
53733 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
53737 * Refreshes the grid
53738 * @param {Boolean} headersToo
53740 refresh : function(headersToo){
53741 this.fireEvent("beforerefresh", this);
53742 this.grid.stopEditing();
53743 var result = this.renderBody();
53744 this.lockedBody.update(result[0]);
53745 this.mainBody.update(result[1]);
53746 if(headersToo === true){
53747 this.updateHeaders();
53748 this.updateColumns();
53749 this.updateSplitters();
53750 this.updateHeaderSortState();
53752 this.syncRowHeights();
53754 this.fireEvent("refresh", this);
53757 handleColumnMove : function(cm, oldIndex, newIndex){
53758 this.indexMap = null;
53759 var s = this.getScrollState();
53760 this.refresh(true);
53761 this.restoreScroll(s);
53762 this.afterMove(newIndex);
53765 afterMove : function(colIndex){
53766 if(this.enableMoveAnim && Roo.enableFx){
53767 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
53769 // if multisort - fix sortOrder, and reload..
53770 if (this.grid.dataSource.multiSort) {
53771 // the we can call sort again..
53772 var dm = this.grid.dataSource;
53773 var cm = this.grid.colModel;
53775 for(var i = 0; i < cm.config.length; i++ ) {
53777 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
53778 continue; // dont' bother, it's not in sort list or being set.
53781 so.push(cm.config[i].dataIndex);
53784 dm.load(dm.lastOptions);
53791 updateCell : function(dm, rowIndex, dataIndex){
53792 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
53793 if(typeof colIndex == "undefined"){ // not present in grid
53796 var cm = this.grid.colModel;
53797 var cell = this.getCell(rowIndex, colIndex);
53798 var cellText = this.getCellText(rowIndex, colIndex);
53801 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
53802 id : cm.getColumnId(colIndex),
53803 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
53805 var renderer = cm.getRenderer(colIndex);
53806 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
53807 if(typeof val == "undefined" || val === "") val = " ";
53808 cellText.innerHTML = val;
53809 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
53810 this.syncRowHeights(rowIndex, rowIndex);
53813 calcColumnWidth : function(colIndex, maxRowsToMeasure){
53815 if(this.grid.autoSizeHeaders){
53816 var h = this.getHeaderCellMeasure(colIndex);
53817 maxWidth = Math.max(maxWidth, h.scrollWidth);
53820 if(this.cm.isLocked(colIndex)){
53821 tb = this.getLockedTable();
53824 tb = this.getBodyTable();
53825 index = colIndex - this.cm.getLockedCount();
53828 var rows = tb.rows;
53829 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
53830 for(var i = 0; i < stopIndex; i++){
53831 var cell = rows[i].childNodes[index].firstChild;
53832 maxWidth = Math.max(maxWidth, cell.scrollWidth);
53835 return maxWidth + /*margin for error in IE*/ 5;
53838 * Autofit a column to its content.
53839 * @param {Number} colIndex
53840 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
53842 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
53843 if(this.cm.isHidden(colIndex)){
53844 return; // can't calc a hidden column
53847 var cid = this.cm.getColumnId(colIndex);
53848 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
53849 if(this.grid.autoSizeHeaders){
53850 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
53853 var newWidth = this.calcColumnWidth(colIndex);
53854 this.cm.setColumnWidth(colIndex,
53855 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
53856 if(!suppressEvent){
53857 this.grid.fireEvent("columnresize", colIndex, newWidth);
53862 * Autofits all columns to their content and then expands to fit any extra space in the grid
53864 autoSizeColumns : function(){
53865 var cm = this.grid.colModel;
53866 var colCount = cm.getColumnCount();
53867 for(var i = 0; i < colCount; i++){
53868 this.autoSizeColumn(i, true, true);
53870 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
53873 this.updateColumns();
53879 * Autofits all columns to the grid's width proportionate with their current size
53880 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
53882 fitColumns : function(reserveScrollSpace){
53883 var cm = this.grid.colModel;
53884 var colCount = cm.getColumnCount();
53888 for (i = 0; i < colCount; i++){
53889 if(!cm.isHidden(i) && !cm.isFixed(i)){
53890 w = cm.getColumnWidth(i);
53896 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
53897 if(reserveScrollSpace){
53900 var frac = (avail - cm.getTotalWidth())/width;
53901 while (cols.length){
53904 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
53906 this.updateColumns();
53910 onRowSelect : function(rowIndex){
53911 var row = this.getRowComposite(rowIndex);
53912 row.addClass("x-grid-row-selected");
53915 onRowDeselect : function(rowIndex){
53916 var row = this.getRowComposite(rowIndex);
53917 row.removeClass("x-grid-row-selected");
53920 onCellSelect : function(row, col){
53921 var cell = this.getCell(row, col);
53923 Roo.fly(cell).addClass("x-grid-cell-selected");
53927 onCellDeselect : function(row, col){
53928 var cell = this.getCell(row, col);
53930 Roo.fly(cell).removeClass("x-grid-cell-selected");
53934 updateHeaderSortState : function(){
53936 // sort state can be single { field: xxx, direction : yyy}
53937 // or { xxx=>ASC , yyy : DESC ..... }
53940 if (!this.ds.multiSort) {
53941 var state = this.ds.getSortState();
53945 mstate[state.field] = state.direction;
53946 // FIXME... - this is not used here.. but might be elsewhere..
53947 this.sortState = state;
53950 mstate = this.ds.sortToggle;
53952 //remove existing sort classes..
53954 var sc = this.sortClasses;
53955 var hds = this.el.select(this.headerSelector).removeClass(sc);
53957 for(var f in mstate) {
53959 var sortColumn = this.cm.findColumnIndex(f);
53961 if(sortColumn != -1){
53962 var sortDir = mstate[f];
53963 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
53972 handleHeaderClick : function(g, index,e){
53974 Roo.log("header click");
53977 // touch events on header are handled by context
53978 this.handleHdCtx(g,index,e);
53983 if(this.headersDisabled){
53986 var dm = g.dataSource, cm = g.colModel;
53987 if(!cm.isSortable(index)){
53992 if (dm.multiSort) {
53993 // update the sortOrder
53995 for(var i = 0; i < cm.config.length; i++ ) {
53997 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
53998 continue; // dont' bother, it's not in sort list or being set.
54001 so.push(cm.config[i].dataIndex);
54007 dm.sort(cm.getDataIndex(index));
54011 destroy : function(){
54013 this.colMenu.removeAll();
54014 Roo.menu.MenuMgr.unregister(this.colMenu);
54015 this.colMenu.getEl().remove();
54016 delete this.colMenu;
54019 this.hmenu.removeAll();
54020 Roo.menu.MenuMgr.unregister(this.hmenu);
54021 this.hmenu.getEl().remove();
54024 if(this.grid.enableColumnMove){
54025 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54027 for(var dd in dds){
54028 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54029 var elid = dds[dd].dragElId;
54031 Roo.get(elid).remove();
54032 } else if(dds[dd].config.isTarget){
54033 dds[dd].proxyTop.remove();
54034 dds[dd].proxyBottom.remove();
54037 if(Roo.dd.DDM.locationCache[dd]){
54038 delete Roo.dd.DDM.locationCache[dd];
54041 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54044 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54045 this.bind(null, null);
54046 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54049 handleLockChange : function(){
54050 this.refresh(true);
54053 onDenyColumnLock : function(){
54057 onDenyColumnHide : function(){
54061 handleHdMenuClick : function(item){
54062 var index = this.hdCtxIndex;
54063 var cm = this.cm, ds = this.ds;
54066 ds.sort(cm.getDataIndex(index), "ASC");
54069 ds.sort(cm.getDataIndex(index), "DESC");
54072 var lc = cm.getLockedCount();
54073 if(cm.getColumnCount(true) <= lc+1){
54074 this.onDenyColumnLock();
54078 cm.setLocked(index, true, true);
54079 cm.moveColumn(index, lc);
54080 this.grid.fireEvent("columnmove", index, lc);
54082 cm.setLocked(index, true);
54086 var lc = cm.getLockedCount();
54087 if((lc-1) != index){
54088 cm.setLocked(index, false, true);
54089 cm.moveColumn(index, lc-1);
54090 this.grid.fireEvent("columnmove", index, lc-1);
54092 cm.setLocked(index, false);
54095 case 'wider': // used to expand cols on touch..
54097 var cw = cm.getColumnWidth(index);
54098 cw += (item.id == 'wider' ? 1 : -1) * 50;
54099 cw = Math.max(0, cw);
54100 cw = Math.min(cw,4000);
54101 cm.setColumnWidth(index, cw);
54105 index = cm.getIndexById(item.id.substr(4));
54107 if(item.checked && cm.getColumnCount(true) <= 1){
54108 this.onDenyColumnHide();
54111 cm.setHidden(index, item.checked);
54117 beforeColMenuShow : function(){
54118 var cm = this.cm, colCount = cm.getColumnCount();
54119 this.colMenu.removeAll();
54120 for(var i = 0; i < colCount; i++){
54121 this.colMenu.add(new Roo.menu.CheckItem({
54122 id: "col-"+cm.getColumnId(i),
54123 text: cm.getColumnHeader(i),
54124 checked: !cm.isHidden(i),
54130 handleHdCtx : function(g, index, e){
54132 var hd = this.getHeaderCell(index);
54133 this.hdCtxIndex = index;
54134 var ms = this.hmenu.items, cm = this.cm;
54135 ms.get("asc").setDisabled(!cm.isSortable(index));
54136 ms.get("desc").setDisabled(!cm.isSortable(index));
54137 if(this.grid.enableColLock !== false){
54138 ms.get("lock").setDisabled(cm.isLocked(index));
54139 ms.get("unlock").setDisabled(!cm.isLocked(index));
54141 this.hmenu.show(hd, "tl-bl");
54144 handleHdOver : function(e){
54145 var hd = this.findHeaderCell(e.getTarget());
54146 if(hd && !this.headersDisabled){
54147 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54148 this.fly(hd).addClass("x-grid-hd-over");
54153 handleHdOut : function(e){
54154 var hd = this.findHeaderCell(e.getTarget());
54156 this.fly(hd).removeClass("x-grid-hd-over");
54160 handleSplitDblClick : function(e, t){
54161 var i = this.getCellIndex(t);
54162 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54163 this.autoSizeColumn(i, true);
54168 render : function(){
54171 var colCount = cm.getColumnCount();
54173 if(this.grid.monitorWindowResize === true){
54174 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54176 var header = this.renderHeaders();
54177 var body = this.templates.body.apply({rows:""});
54178 var html = this.templates.master.apply({
54181 lockedHeader: header[0],
54185 //this.updateColumns();
54187 this.grid.getGridEl().dom.innerHTML = html;
54189 this.initElements();
54191 // a kludge to fix the random scolling effect in webkit
54192 this.el.on("scroll", function() {
54193 this.el.dom.scrollTop=0; // hopefully not recursive..
54196 this.scroller.on("scroll", this.handleScroll, this);
54197 this.lockedBody.on("mousewheel", this.handleWheel, this);
54198 this.mainBody.on("mousewheel", this.handleWheel, this);
54200 this.mainHd.on("mouseover", this.handleHdOver, this);
54201 this.mainHd.on("mouseout", this.handleHdOut, this);
54202 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54203 {delegate: "."+this.splitClass});
54205 this.lockedHd.on("mouseover", this.handleHdOver, this);
54206 this.lockedHd.on("mouseout", this.handleHdOut, this);
54207 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54208 {delegate: "."+this.splitClass});
54210 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54211 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54214 this.updateSplitters();
54216 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54217 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54218 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54221 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54222 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54224 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54225 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54227 if(this.grid.enableColLock !== false){
54228 this.hmenu.add('-',
54229 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54230 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54234 this.hmenu.add('-',
54235 {id:"wider", text: this.columnsWiderText},
54236 {id:"narrow", text: this.columnsNarrowText }
54242 if(this.grid.enableColumnHide !== false){
54244 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54245 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54246 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54248 this.hmenu.add('-',
54249 {id:"columns", text: this.columnsText, menu: this.colMenu}
54252 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54254 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54257 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54258 this.dd = new Roo.grid.GridDragZone(this.grid, {
54259 ddGroup : this.grid.ddGroup || 'GridDD'
54265 for(var i = 0; i < colCount; i++){
54266 if(cm.isHidden(i)){
54267 this.hideColumn(i);
54269 if(cm.config[i].align){
54270 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54271 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54275 this.updateHeaderSortState();
54277 this.beforeInitialResize();
54280 // two part rendering gives faster view to the user
54281 this.renderPhase2.defer(1, this);
54284 renderPhase2 : function(){
54285 // render the rows now
54287 if(this.grid.autoSizeColumns){
54288 this.autoSizeColumns();
54292 beforeInitialResize : function(){
54296 onColumnSplitterMoved : function(i, w){
54297 this.userResized = true;
54298 var cm = this.grid.colModel;
54299 cm.setColumnWidth(i, w, true);
54300 var cid = cm.getColumnId(i);
54301 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54302 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54303 this.updateSplitters();
54305 this.grid.fireEvent("columnresize", i, w);
54308 syncRowHeights : function(startIndex, endIndex){
54309 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54310 startIndex = startIndex || 0;
54311 var mrows = this.getBodyTable().rows;
54312 var lrows = this.getLockedTable().rows;
54313 var len = mrows.length-1;
54314 endIndex = Math.min(endIndex || len, len);
54315 for(var i = startIndex; i <= endIndex; i++){
54316 var m = mrows[i], l = lrows[i];
54317 var h = Math.max(m.offsetHeight, l.offsetHeight);
54318 m.style.height = l.style.height = h + "px";
54323 layout : function(initialRender, is2ndPass){
54325 var auto = g.autoHeight;
54326 var scrollOffset = 16;
54327 var c = g.getGridEl(), cm = this.cm,
54328 expandCol = g.autoExpandColumn,
54330 //c.beginMeasure();
54332 if(!c.dom.offsetWidth){ // display:none?
54334 this.lockedWrap.show();
54335 this.mainWrap.show();
54340 var hasLock = this.cm.isLocked(0);
54342 var tbh = this.headerPanel.getHeight();
54343 var bbh = this.footerPanel.getHeight();
54346 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54347 var newHeight = ch + c.getBorderWidth("tb");
54349 newHeight = Math.min(g.maxHeight, newHeight);
54351 c.setHeight(newHeight);
54355 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54358 var s = this.scroller;
54360 var csize = c.getSize(true);
54362 this.el.setSize(csize.width, csize.height);
54364 this.headerPanel.setWidth(csize.width);
54365 this.footerPanel.setWidth(csize.width);
54367 var hdHeight = this.mainHd.getHeight();
54368 var vw = csize.width;
54369 var vh = csize.height - (tbh + bbh);
54373 var bt = this.getBodyTable();
54374 var ltWidth = hasLock ?
54375 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54377 var scrollHeight = bt.offsetHeight;
54378 var scrollWidth = ltWidth + bt.offsetWidth;
54379 var vscroll = false, hscroll = false;
54381 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54383 var lw = this.lockedWrap, mw = this.mainWrap;
54384 var lb = this.lockedBody, mb = this.mainBody;
54386 setTimeout(function(){
54387 var t = s.dom.offsetTop;
54388 var w = s.dom.clientWidth,
54389 h = s.dom.clientHeight;
54392 lw.setSize(ltWidth, h);
54394 mw.setLeftTop(ltWidth, t);
54395 mw.setSize(w-ltWidth, h);
54397 lb.setHeight(h-hdHeight);
54398 mb.setHeight(h-hdHeight);
54400 if(is2ndPass !== true && !gv.userResized && expandCol){
54401 // high speed resize without full column calculation
54403 var ci = cm.getIndexById(expandCol);
54405 ci = cm.findColumnIndex(expandCol);
54407 ci = Math.max(0, ci); // make sure it's got at least the first col.
54408 var expandId = cm.getColumnId(ci);
54409 var tw = cm.getTotalWidth(false);
54410 var currentWidth = cm.getColumnWidth(ci);
54411 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54412 if(currentWidth != cw){
54413 cm.setColumnWidth(ci, cw, true);
54414 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54415 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54416 gv.updateSplitters();
54417 gv.layout(false, true);
54429 onWindowResize : function(){
54430 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
54436 appendFooter : function(parentEl){
54440 sortAscText : "Sort Ascending",
54441 sortDescText : "Sort Descending",
54442 lockText : "Lock Column",
54443 unlockText : "Unlock Column",
54444 columnsText : "Columns",
54446 columnsWiderText : "Wider",
54447 columnsNarrowText : "Thinner"
54451 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
54452 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
54453 this.proxy.el.addClass('x-grid3-col-dd');
54456 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
54457 handleMouseDown : function(e){
54461 callHandleMouseDown : function(e){
54462 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
54467 * Ext JS Library 1.1.1
54468 * Copyright(c) 2006-2007, Ext JS, LLC.
54470 * Originally Released Under LGPL - original licence link has changed is not relivant.
54473 * <script type="text/javascript">
54477 // This is a support class used internally by the Grid components
54478 Roo.grid.SplitDragZone = function(grid, hd, hd2){
54480 this.view = grid.getView();
54481 this.proxy = this.view.resizeProxy;
54482 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
54483 "gridSplitters" + this.grid.getGridEl().id, {
54484 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
54486 this.setHandleElId(Roo.id(hd));
54487 this.setOuterHandleElId(Roo.id(hd2));
54488 this.scroll = false;
54490 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
54491 fly: Roo.Element.fly,
54493 b4StartDrag : function(x, y){
54494 this.view.headersDisabled = true;
54495 this.proxy.setHeight(this.view.mainWrap.getHeight());
54496 var w = this.cm.getColumnWidth(this.cellIndex);
54497 var minw = Math.max(w-this.grid.minColumnWidth, 0);
54498 this.resetConstraints();
54499 this.setXConstraint(minw, 1000);
54500 this.setYConstraint(0, 0);
54501 this.minX = x - minw;
54502 this.maxX = x + 1000;
54504 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
54508 handleMouseDown : function(e){
54509 ev = Roo.EventObject.setEvent(e);
54510 var t = this.fly(ev.getTarget());
54511 if(t.hasClass("x-grid-split")){
54512 this.cellIndex = this.view.getCellIndex(t.dom);
54513 this.split = t.dom;
54514 this.cm = this.grid.colModel;
54515 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
54516 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
54521 endDrag : function(e){
54522 this.view.headersDisabled = false;
54523 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
54524 var diff = endX - this.startPos;
54525 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
54528 autoOffset : function(){
54529 this.setDelta(0,0);
54533 * Ext JS Library 1.1.1
54534 * Copyright(c) 2006-2007, Ext JS, LLC.
54536 * Originally Released Under LGPL - original licence link has changed is not relivant.
54539 * <script type="text/javascript">
54543 // This is a support class used internally by the Grid components
54544 Roo.grid.GridDragZone = function(grid, config){
54545 this.view = grid.getView();
54546 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
54547 if(this.view.lockedBody){
54548 this.setHandleElId(Roo.id(this.view.mainBody.dom));
54549 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
54551 this.scroll = false;
54553 this.ddel = document.createElement('div');
54554 this.ddel.className = 'x-grid-dd-wrap';
54557 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
54558 ddGroup : "GridDD",
54560 getDragData : function(e){
54561 var t = Roo.lib.Event.getTarget(e);
54562 var rowIndex = this.view.findRowIndex(t);
54563 var sm = this.grid.selModel;
54565 //Roo.log(rowIndex);
54567 if (sm.getSelectedCell) {
54568 // cell selection..
54569 if (!sm.getSelectedCell()) {
54572 if (rowIndex != sm.getSelectedCell()[0]) {
54578 if(rowIndex !== false){
54583 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
54585 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
54588 if (e.hasModifier()){
54589 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
54592 Roo.log("getDragData");
54597 rowIndex: rowIndex,
54598 selections:sm.getSelections ? sm.getSelections() : (
54599 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
54606 onInitDrag : function(e){
54607 var data = this.dragData;
54608 this.ddel.innerHTML = this.grid.getDragDropText();
54609 this.proxy.update(this.ddel);
54610 // fire start drag?
54613 afterRepair : function(){
54614 this.dragging = false;
54617 getRepairXY : function(e, data){
54621 onEndDrag : function(data, e){
54625 onValidDrop : function(dd, e, id){
54630 beforeInvalidDrop : function(e, id){
54635 * Ext JS Library 1.1.1
54636 * Copyright(c) 2006-2007, Ext JS, LLC.
54638 * Originally Released Under LGPL - original licence link has changed is not relivant.
54641 * <script type="text/javascript">
54646 * @class Roo.grid.ColumnModel
54647 * @extends Roo.util.Observable
54648 * This is the default implementation of a ColumnModel used by the Grid. It defines
54649 * the columns in the grid.
54652 var colModel = new Roo.grid.ColumnModel([
54653 {header: "Ticker", width: 60, sortable: true, locked: true},
54654 {header: "Company Name", width: 150, sortable: true},
54655 {header: "Market Cap.", width: 100, sortable: true},
54656 {header: "$ Sales", width: 100, sortable: true, renderer: money},
54657 {header: "Employees", width: 100, sortable: true, resizable: false}
54662 * The config options listed for this class are options which may appear in each
54663 * individual column definition.
54664 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
54666 * @param {Object} config An Array of column config objects. See this class's
54667 * config objects for details.
54669 Roo.grid.ColumnModel = function(config){
54671 * The config passed into the constructor
54673 this.config = config;
54676 // if no id, create one
54677 // if the column does not have a dataIndex mapping,
54678 // map it to the order it is in the config
54679 for(var i = 0, len = config.length; i < len; i++){
54681 if(typeof c.dataIndex == "undefined"){
54684 if(typeof c.renderer == "string"){
54685 c.renderer = Roo.util.Format[c.renderer];
54687 if(typeof c.id == "undefined"){
54690 if(c.editor && c.editor.xtype){
54691 c.editor = Roo.factory(c.editor, Roo.grid);
54693 if(c.editor && c.editor.isFormField){
54694 c.editor = new Roo.grid.GridEditor(c.editor);
54696 this.lookup[c.id] = c;
54700 * The width of columns which have no width specified (defaults to 100)
54703 this.defaultWidth = 100;
54706 * Default sortable of columns which have no sortable specified (defaults to false)
54709 this.defaultSortable = false;
54713 * @event widthchange
54714 * Fires when the width of a column changes.
54715 * @param {ColumnModel} this
54716 * @param {Number} columnIndex The column index
54717 * @param {Number} newWidth The new width
54719 "widthchange": true,
54721 * @event headerchange
54722 * Fires when the text of a header changes.
54723 * @param {ColumnModel} this
54724 * @param {Number} columnIndex The column index
54725 * @param {Number} newText The new header text
54727 "headerchange": true,
54729 * @event hiddenchange
54730 * Fires when a column is hidden or "unhidden".
54731 * @param {ColumnModel} this
54732 * @param {Number} columnIndex The column index
54733 * @param {Boolean} hidden true if hidden, false otherwise
54735 "hiddenchange": true,
54737 * @event columnmoved
54738 * Fires when a column is moved.
54739 * @param {ColumnModel} this
54740 * @param {Number} oldIndex
54741 * @param {Number} newIndex
54743 "columnmoved" : true,
54745 * @event columlockchange
54746 * Fires when a column's locked state is changed
54747 * @param {ColumnModel} this
54748 * @param {Number} colIndex
54749 * @param {Boolean} locked true if locked
54751 "columnlockchange" : true
54753 Roo.grid.ColumnModel.superclass.constructor.call(this);
54755 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
54757 * @cfg {String} header The header text to display in the Grid view.
54760 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
54761 * {@link Roo.data.Record} definition from which to draw the column's value. If not
54762 * specified, the column's index is used as an index into the Record's data Array.
54765 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
54766 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
54769 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
54770 * Defaults to the value of the {@link #defaultSortable} property.
54771 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
54774 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
54777 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
54780 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
54783 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
54786 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
54787 * given the cell's data value. See {@link #setRenderer}. If not specified, the
54788 * default renderer uses the raw data value.
54791 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
54794 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
54798 * Returns the id of the column at the specified index.
54799 * @param {Number} index The column index
54800 * @return {String} the id
54802 getColumnId : function(index){
54803 return this.config[index].id;
54807 * Returns the column for a specified id.
54808 * @param {String} id The column id
54809 * @return {Object} the column
54811 getColumnById : function(id){
54812 return this.lookup[id];
54817 * Returns the column for a specified dataIndex.
54818 * @param {String} dataIndex The column dataIndex
54819 * @return {Object|Boolean} the column or false if not found
54821 getColumnByDataIndex: function(dataIndex){
54822 var index = this.findColumnIndex(dataIndex);
54823 return index > -1 ? this.config[index] : false;
54827 * Returns the index for a specified column id.
54828 * @param {String} id The column id
54829 * @return {Number} the index, or -1 if not found
54831 getIndexById : function(id){
54832 for(var i = 0, len = this.config.length; i < len; i++){
54833 if(this.config[i].id == id){
54841 * Returns the index for a specified column dataIndex.
54842 * @param {String} dataIndex The column dataIndex
54843 * @return {Number} the index, or -1 if not found
54846 findColumnIndex : function(dataIndex){
54847 for(var i = 0, len = this.config.length; i < len; i++){
54848 if(this.config[i].dataIndex == dataIndex){
54856 moveColumn : function(oldIndex, newIndex){
54857 var c = this.config[oldIndex];
54858 this.config.splice(oldIndex, 1);
54859 this.config.splice(newIndex, 0, c);
54860 this.dataMap = null;
54861 this.fireEvent("columnmoved", this, oldIndex, newIndex);
54864 isLocked : function(colIndex){
54865 return this.config[colIndex].locked === true;
54868 setLocked : function(colIndex, value, suppressEvent){
54869 if(this.isLocked(colIndex) == value){
54872 this.config[colIndex].locked = value;
54873 if(!suppressEvent){
54874 this.fireEvent("columnlockchange", this, colIndex, value);
54878 getTotalLockedWidth : function(){
54879 var totalWidth = 0;
54880 for(var i = 0; i < this.config.length; i++){
54881 if(this.isLocked(i) && !this.isHidden(i)){
54882 this.totalWidth += this.getColumnWidth(i);
54888 getLockedCount : function(){
54889 for(var i = 0, len = this.config.length; i < len; i++){
54890 if(!this.isLocked(i)){
54897 * Returns the number of columns.
54900 getColumnCount : function(visibleOnly){
54901 if(visibleOnly === true){
54903 for(var i = 0, len = this.config.length; i < len; i++){
54904 if(!this.isHidden(i)){
54910 return this.config.length;
54914 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
54915 * @param {Function} fn
54916 * @param {Object} scope (optional)
54917 * @return {Array} result
54919 getColumnsBy : function(fn, scope){
54921 for(var i = 0, len = this.config.length; i < len; i++){
54922 var c = this.config[i];
54923 if(fn.call(scope||this, c, i) === true){
54931 * Returns true if the specified column is sortable.
54932 * @param {Number} col The column index
54933 * @return {Boolean}
54935 isSortable : function(col){
54936 if(typeof this.config[col].sortable == "undefined"){
54937 return this.defaultSortable;
54939 return this.config[col].sortable;
54943 * Returns the rendering (formatting) function defined for the column.
54944 * @param {Number} col The column index.
54945 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
54947 getRenderer : function(col){
54948 if(!this.config[col].renderer){
54949 return Roo.grid.ColumnModel.defaultRenderer;
54951 return this.config[col].renderer;
54955 * Sets the rendering (formatting) function for a column.
54956 * @param {Number} col The column index
54957 * @param {Function} fn The function to use to process the cell's raw data
54958 * to return HTML markup for the grid view. The render function is called with
54959 * the following parameters:<ul>
54960 * <li>Data value.</li>
54961 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
54962 * <li>css A CSS style string to apply to the table cell.</li>
54963 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
54964 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
54965 * <li>Row index</li>
54966 * <li>Column index</li>
54967 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
54969 setRenderer : function(col, fn){
54970 this.config[col].renderer = fn;
54974 * Returns the width for the specified column.
54975 * @param {Number} col The column index
54978 getColumnWidth : function(col){
54979 return this.config[col].width * 1 || this.defaultWidth;
54983 * Sets the width for a column.
54984 * @param {Number} col The column index
54985 * @param {Number} width The new width
54987 setColumnWidth : function(col, width, suppressEvent){
54988 this.config[col].width = width;
54989 this.totalWidth = null;
54990 if(!suppressEvent){
54991 this.fireEvent("widthchange", this, col, width);
54996 * Returns the total width of all columns.
54997 * @param {Boolean} includeHidden True to include hidden column widths
55000 getTotalWidth : function(includeHidden){
55001 if(!this.totalWidth){
55002 this.totalWidth = 0;
55003 for(var i = 0, len = this.config.length; i < len; i++){
55004 if(includeHidden || !this.isHidden(i)){
55005 this.totalWidth += this.getColumnWidth(i);
55009 return this.totalWidth;
55013 * Returns the header for the specified column.
55014 * @param {Number} col The column index
55017 getColumnHeader : function(col){
55018 return this.config[col].header;
55022 * Sets the header for a column.
55023 * @param {Number} col The column index
55024 * @param {String} header The new header
55026 setColumnHeader : function(col, header){
55027 this.config[col].header = header;
55028 this.fireEvent("headerchange", this, col, header);
55032 * Returns the tooltip for the specified column.
55033 * @param {Number} col The column index
55036 getColumnTooltip : function(col){
55037 return this.config[col].tooltip;
55040 * Sets the tooltip for a column.
55041 * @param {Number} col The column index
55042 * @param {String} tooltip The new tooltip
55044 setColumnTooltip : function(col, tooltip){
55045 this.config[col].tooltip = tooltip;
55049 * Returns the dataIndex for the specified column.
55050 * @param {Number} col The column index
55053 getDataIndex : function(col){
55054 return this.config[col].dataIndex;
55058 * Sets the dataIndex for a column.
55059 * @param {Number} col The column index
55060 * @param {Number} dataIndex The new dataIndex
55062 setDataIndex : function(col, dataIndex){
55063 this.config[col].dataIndex = dataIndex;
55069 * Returns true if the cell is editable.
55070 * @param {Number} colIndex The column index
55071 * @param {Number} rowIndex The row index
55072 * @return {Boolean}
55074 isCellEditable : function(colIndex, rowIndex){
55075 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55079 * Returns the editor defined for the cell/column.
55080 * return false or null to disable editing.
55081 * @param {Number} colIndex The column index
55082 * @param {Number} rowIndex The row index
55085 getCellEditor : function(colIndex, rowIndex){
55086 return this.config[colIndex].editor;
55090 * Sets if a column is editable.
55091 * @param {Number} col The column index
55092 * @param {Boolean} editable True if the column is editable
55094 setEditable : function(col, editable){
55095 this.config[col].editable = editable;
55100 * Returns true if the column is hidden.
55101 * @param {Number} colIndex The column index
55102 * @return {Boolean}
55104 isHidden : function(colIndex){
55105 return this.config[colIndex].hidden;
55110 * Returns true if the column width cannot be changed
55112 isFixed : function(colIndex){
55113 return this.config[colIndex].fixed;
55117 * Returns true if the column can be resized
55118 * @return {Boolean}
55120 isResizable : function(colIndex){
55121 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55124 * Sets if a column is hidden.
55125 * @param {Number} colIndex The column index
55126 * @param {Boolean} hidden True if the column is hidden
55128 setHidden : function(colIndex, hidden){
55129 this.config[colIndex].hidden = hidden;
55130 this.totalWidth = null;
55131 this.fireEvent("hiddenchange", this, colIndex, hidden);
55135 * Sets the editor for a column.
55136 * @param {Number} col The column index
55137 * @param {Object} editor The editor object
55139 setEditor : function(col, editor){
55140 this.config[col].editor = editor;
55144 Roo.grid.ColumnModel.defaultRenderer = function(value){
55145 if(typeof value == "string" && value.length < 1){
55151 // Alias for backwards compatibility
55152 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55155 * Ext JS Library 1.1.1
55156 * Copyright(c) 2006-2007, Ext JS, LLC.
55158 * Originally Released Under LGPL - original licence link has changed is not relivant.
55161 * <script type="text/javascript">
55165 * @class Roo.grid.AbstractSelectionModel
55166 * @extends Roo.util.Observable
55167 * Abstract base class for grid SelectionModels. It provides the interface that should be
55168 * implemented by descendant classes. This class should not be directly instantiated.
55171 Roo.grid.AbstractSelectionModel = function(){
55172 this.locked = false;
55173 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55176 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55177 /** @ignore Called by the grid automatically. Do not call directly. */
55178 init : function(grid){
55184 * Locks the selections.
55187 this.locked = true;
55191 * Unlocks the selections.
55193 unlock : function(){
55194 this.locked = false;
55198 * Returns true if the selections are locked.
55199 * @return {Boolean}
55201 isLocked : function(){
55202 return this.locked;
55206 * Ext JS Library 1.1.1
55207 * Copyright(c) 2006-2007, Ext JS, LLC.
55209 * Originally Released Under LGPL - original licence link has changed is not relivant.
55212 * <script type="text/javascript">
55215 * @extends Roo.grid.AbstractSelectionModel
55216 * @class Roo.grid.RowSelectionModel
55217 * The default SelectionModel used by {@link Roo.grid.Grid}.
55218 * It supports multiple selections and keyboard selection/navigation.
55220 * @param {Object} config
55222 Roo.grid.RowSelectionModel = function(config){
55223 Roo.apply(this, config);
55224 this.selections = new Roo.util.MixedCollection(false, function(o){
55229 this.lastActive = false;
55233 * @event selectionchange
55234 * Fires when the selection changes
55235 * @param {SelectionModel} this
55237 "selectionchange" : true,
55239 * @event afterselectionchange
55240 * Fires after the selection changes (eg. by key press or clicking)
55241 * @param {SelectionModel} this
55243 "afterselectionchange" : true,
55245 * @event beforerowselect
55246 * Fires when a row is selected being selected, return false to cancel.
55247 * @param {SelectionModel} this
55248 * @param {Number} rowIndex The selected index
55249 * @param {Boolean} keepExisting False if other selections will be cleared
55251 "beforerowselect" : true,
55254 * Fires when a row is selected.
55255 * @param {SelectionModel} this
55256 * @param {Number} rowIndex The selected index
55257 * @param {Roo.data.Record} r The record
55259 "rowselect" : true,
55261 * @event rowdeselect
55262 * Fires when a row is deselected.
55263 * @param {SelectionModel} this
55264 * @param {Number} rowIndex The selected index
55266 "rowdeselect" : true
55268 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55269 this.locked = false;
55272 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55274 * @cfg {Boolean} singleSelect
55275 * True to allow selection of only one row at a time (defaults to false)
55277 singleSelect : false,
55280 initEvents : function(){
55282 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55283 this.grid.on("mousedown", this.handleMouseDown, this);
55284 }else{ // allow click to work like normal
55285 this.grid.on("rowclick", this.handleDragableRowClick, this);
55288 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55289 "up" : function(e){
55291 this.selectPrevious(e.shiftKey);
55292 }else if(this.last !== false && this.lastActive !== false){
55293 var last = this.last;
55294 this.selectRange(this.last, this.lastActive-1);
55295 this.grid.getView().focusRow(this.lastActive);
55296 if(last !== false){
55300 this.selectFirstRow();
55302 this.fireEvent("afterselectionchange", this);
55304 "down" : function(e){
55306 this.selectNext(e.shiftKey);
55307 }else if(this.last !== false && this.lastActive !== false){
55308 var last = this.last;
55309 this.selectRange(this.last, this.lastActive+1);
55310 this.grid.getView().focusRow(this.lastActive);
55311 if(last !== false){
55315 this.selectFirstRow();
55317 this.fireEvent("afterselectionchange", this);
55322 var view = this.grid.view;
55323 view.on("refresh", this.onRefresh, this);
55324 view.on("rowupdated", this.onRowUpdated, this);
55325 view.on("rowremoved", this.onRemove, this);
55329 onRefresh : function(){
55330 var ds = this.grid.dataSource, i, v = this.grid.view;
55331 var s = this.selections;
55332 s.each(function(r){
55333 if((i = ds.indexOfId(r.id)) != -1){
55342 onRemove : function(v, index, r){
55343 this.selections.remove(r);
55347 onRowUpdated : function(v, index, r){
55348 if(this.isSelected(r)){
55349 v.onRowSelect(index);
55355 * @param {Array} records The records to select
55356 * @param {Boolean} keepExisting (optional) True to keep existing selections
55358 selectRecords : function(records, keepExisting){
55360 this.clearSelections();
55362 var ds = this.grid.dataSource;
55363 for(var i = 0, len = records.length; i < len; i++){
55364 this.selectRow(ds.indexOf(records[i]), true);
55369 * Gets the number of selected rows.
55372 getCount : function(){
55373 return this.selections.length;
55377 * Selects the first row in the grid.
55379 selectFirstRow : function(){
55384 * Select the last row.
55385 * @param {Boolean} keepExisting (optional) True to keep existing selections
55387 selectLastRow : function(keepExisting){
55388 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55392 * Selects the row immediately following the last selected row.
55393 * @param {Boolean} keepExisting (optional) True to keep existing selections
55395 selectNext : function(keepExisting){
55396 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55397 this.selectRow(this.last+1, keepExisting);
55398 this.grid.getView().focusRow(this.last);
55403 * Selects the row that precedes the last selected row.
55404 * @param {Boolean} keepExisting (optional) True to keep existing selections
55406 selectPrevious : function(keepExisting){
55408 this.selectRow(this.last-1, keepExisting);
55409 this.grid.getView().focusRow(this.last);
55414 * Returns the selected records
55415 * @return {Array} Array of selected records
55417 getSelections : function(){
55418 return [].concat(this.selections.items);
55422 * Returns the first selected record.
55425 getSelected : function(){
55426 return this.selections.itemAt(0);
55431 * Clears all selections.
55433 clearSelections : function(fast){
55434 if(this.locked) return;
55436 var ds = this.grid.dataSource;
55437 var s = this.selections;
55438 s.each(function(r){
55439 this.deselectRow(ds.indexOfId(r.id));
55443 this.selections.clear();
55450 * Selects all rows.
55452 selectAll : function(){
55453 if(this.locked) return;
55454 this.selections.clear();
55455 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
55456 this.selectRow(i, true);
55461 * Returns True if there is a selection.
55462 * @return {Boolean}
55464 hasSelection : function(){
55465 return this.selections.length > 0;
55469 * Returns True if the specified row is selected.
55470 * @param {Number/Record} record The record or index of the record to check
55471 * @return {Boolean}
55473 isSelected : function(index){
55474 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
55475 return (r && this.selections.key(r.id) ? true : false);
55479 * Returns True if the specified record id is selected.
55480 * @param {String} id The id of record to check
55481 * @return {Boolean}
55483 isIdSelected : function(id){
55484 return (this.selections.key(id) ? true : false);
55488 handleMouseDown : function(e, t){
55489 var view = this.grid.getView(), rowIndex;
55490 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
55493 if(e.shiftKey && this.last !== false){
55494 var last = this.last;
55495 this.selectRange(last, rowIndex, e.ctrlKey);
55496 this.last = last; // reset the last
55497 view.focusRow(rowIndex);
55499 var isSelected = this.isSelected(rowIndex);
55500 if(e.button !== 0 && isSelected){
55501 view.focusRow(rowIndex);
55502 }else if(e.ctrlKey && isSelected){
55503 this.deselectRow(rowIndex);
55504 }else if(!isSelected){
55505 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
55506 view.focusRow(rowIndex);
55509 this.fireEvent("afterselectionchange", this);
55512 handleDragableRowClick : function(grid, rowIndex, e)
55514 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
55515 this.selectRow(rowIndex, false);
55516 grid.view.focusRow(rowIndex);
55517 this.fireEvent("afterselectionchange", this);
55522 * Selects multiple rows.
55523 * @param {Array} rows Array of the indexes of the row to select
55524 * @param {Boolean} keepExisting (optional) True to keep existing selections
55526 selectRows : function(rows, keepExisting){
55528 this.clearSelections();
55530 for(var i = 0, len = rows.length; i < len; i++){
55531 this.selectRow(rows[i], true);
55536 * Selects a range of rows. All rows in between startRow and endRow are also selected.
55537 * @param {Number} startRow The index of the first row in the range
55538 * @param {Number} endRow The index of the last row in the range
55539 * @param {Boolean} keepExisting (optional) True to retain existing selections
55541 selectRange : function(startRow, endRow, keepExisting){
55542 if(this.locked) return;
55544 this.clearSelections();
55546 if(startRow <= endRow){
55547 for(var i = startRow; i <= endRow; i++){
55548 this.selectRow(i, true);
55551 for(var i = startRow; i >= endRow; i--){
55552 this.selectRow(i, true);
55558 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
55559 * @param {Number} startRow The index of the first row in the range
55560 * @param {Number} endRow The index of the last row in the range
55562 deselectRange : function(startRow, endRow, preventViewNotify){
55563 if(this.locked) return;
55564 for(var i = startRow; i <= endRow; i++){
55565 this.deselectRow(i, preventViewNotify);
55571 * @param {Number} row The index of the row to select
55572 * @param {Boolean} keepExisting (optional) True to keep existing selections
55574 selectRow : function(index, keepExisting, preventViewNotify){
55575 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
55576 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
55577 if(!keepExisting || this.singleSelect){
55578 this.clearSelections();
55580 var r = this.grid.dataSource.getAt(index);
55581 this.selections.add(r);
55582 this.last = this.lastActive = index;
55583 if(!preventViewNotify){
55584 this.grid.getView().onRowSelect(index);
55586 this.fireEvent("rowselect", this, index, r);
55587 this.fireEvent("selectionchange", this);
55593 * @param {Number} row The index of the row to deselect
55595 deselectRow : function(index, preventViewNotify){
55596 if(this.locked) return;
55597 if(this.last == index){
55600 if(this.lastActive == index){
55601 this.lastActive = false;
55603 var r = this.grid.dataSource.getAt(index);
55604 this.selections.remove(r);
55605 if(!preventViewNotify){
55606 this.grid.getView().onRowDeselect(index);
55608 this.fireEvent("rowdeselect", this, index);
55609 this.fireEvent("selectionchange", this);
55613 restoreLast : function(){
55615 this.last = this._last;
55620 acceptsNav : function(row, col, cm){
55621 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55625 onEditorKey : function(field, e){
55626 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
55631 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55633 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55635 }else if(k == e.ENTER && !e.ctrlKey){
55639 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
55641 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
55643 }else if(k == e.ESC){
55647 g.startEditing(newCell[0], newCell[1]);
55652 * Ext JS Library 1.1.1
55653 * Copyright(c) 2006-2007, Ext JS, LLC.
55655 * Originally Released Under LGPL - original licence link has changed is not relivant.
55658 * <script type="text/javascript">
55661 * @class Roo.grid.CellSelectionModel
55662 * @extends Roo.grid.AbstractSelectionModel
55663 * This class provides the basic implementation for cell selection in a grid.
55665 * @param {Object} config The object containing the configuration of this model.
55666 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
55668 Roo.grid.CellSelectionModel = function(config){
55669 Roo.apply(this, config);
55671 this.selection = null;
55675 * @event beforerowselect
55676 * Fires before a cell is selected.
55677 * @param {SelectionModel} this
55678 * @param {Number} rowIndex The selected row index
55679 * @param {Number} colIndex The selected cell index
55681 "beforecellselect" : true,
55683 * @event cellselect
55684 * Fires when a cell is selected.
55685 * @param {SelectionModel} this
55686 * @param {Number} rowIndex The selected row index
55687 * @param {Number} colIndex The selected cell index
55689 "cellselect" : true,
55691 * @event selectionchange
55692 * Fires when the active selection changes.
55693 * @param {SelectionModel} this
55694 * @param {Object} selection null for no selection or an object (o) with two properties
55696 <li>o.record: the record object for the row the selection is in</li>
55697 <li>o.cell: An array of [rowIndex, columnIndex]</li>
55700 "selectionchange" : true,
55703 * Fires when the tab (or enter) was pressed on the last editable cell
55704 * You can use this to trigger add new row.
55705 * @param {SelectionModel} this
55709 * @event beforeeditnext
55710 * Fires before the next editable sell is made active
55711 * You can use this to skip to another cell or fire the tabend
55712 * if you set cell to false
55713 * @param {Object} eventdata object : { cell : [ row, col ] }
55715 "beforeeditnext" : true
55717 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
55720 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
55722 enter_is_tab: false,
55725 initEvents : function(){
55726 this.grid.on("mousedown", this.handleMouseDown, this);
55727 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
55728 var view = this.grid.view;
55729 view.on("refresh", this.onViewChange, this);
55730 view.on("rowupdated", this.onRowUpdated, this);
55731 view.on("beforerowremoved", this.clearSelections, this);
55732 view.on("beforerowsinserted", this.clearSelections, this);
55733 if(this.grid.isEditor){
55734 this.grid.on("beforeedit", this.beforeEdit, this);
55739 beforeEdit : function(e){
55740 this.select(e.row, e.column, false, true, e.record);
55744 onRowUpdated : function(v, index, r){
55745 if(this.selection && this.selection.record == r){
55746 v.onCellSelect(index, this.selection.cell[1]);
55751 onViewChange : function(){
55752 this.clearSelections(true);
55756 * Returns the currently selected cell,.
55757 * @return {Array} The selected cell (row, column) or null if none selected.
55759 getSelectedCell : function(){
55760 return this.selection ? this.selection.cell : null;
55764 * Clears all selections.
55765 * @param {Boolean} true to prevent the gridview from being notified about the change.
55767 clearSelections : function(preventNotify){
55768 var s = this.selection;
55770 if(preventNotify !== true){
55771 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
55773 this.selection = null;
55774 this.fireEvent("selectionchange", this, null);
55779 * Returns true if there is a selection.
55780 * @return {Boolean}
55782 hasSelection : function(){
55783 return this.selection ? true : false;
55787 handleMouseDown : function(e, t){
55788 var v = this.grid.getView();
55789 if(this.isLocked()){
55792 var row = v.findRowIndex(t);
55793 var cell = v.findCellIndex(t);
55794 if(row !== false && cell !== false){
55795 this.select(row, cell);
55801 * @param {Number} rowIndex
55802 * @param {Number} collIndex
55804 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
55805 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
55806 this.clearSelections();
55807 r = r || this.grid.dataSource.getAt(rowIndex);
55810 cell : [rowIndex, colIndex]
55812 if(!preventViewNotify){
55813 var v = this.grid.getView();
55814 v.onCellSelect(rowIndex, colIndex);
55815 if(preventFocus !== true){
55816 v.focusCell(rowIndex, colIndex);
55819 this.fireEvent("cellselect", this, rowIndex, colIndex);
55820 this.fireEvent("selectionchange", this, this.selection);
55825 isSelectable : function(rowIndex, colIndex, cm){
55826 return !cm.isHidden(colIndex);
55830 handleKeyDown : function(e){
55831 //Roo.log('Cell Sel Model handleKeyDown');
55832 if(!e.isNavKeyPress()){
55835 var g = this.grid, s = this.selection;
55838 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
55840 this.select(cell[0], cell[1]);
55845 var walk = function(row, col, step){
55846 return g.walkCells(row, col, step, sm.isSelectable, sm);
55848 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
55855 // handled by onEditorKey
55856 if (g.isEditor && g.editing) {
55860 newCell = walk(r, c-1, -1);
55862 newCell = walk(r, c+1, 1);
55867 newCell = walk(r+1, c, 1);
55871 newCell = walk(r-1, c, -1);
55875 newCell = walk(r, c+1, 1);
55879 newCell = walk(r, c-1, -1);
55884 if(g.isEditor && !g.editing){
55885 g.startEditing(r, c);
55894 this.select(newCell[0], newCell[1]);
55900 acceptsNav : function(row, col, cm){
55901 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55905 * @param {Number} field (not used) - as it's normally used as a listener
55906 * @param {Number} e - event - fake it by using
55908 * var e = Roo.EventObjectImpl.prototype;
55909 * e.keyCode = e.TAB
55913 onEditorKey : function(field, e){
55915 var k = e.getKey(),
55918 ed = g.activeEditor,
55920 ///Roo.log('onEditorKey' + k);
55923 if (this.enter_is_tab && k == e.ENTER) {
55929 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55931 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55937 } else if(k == e.ENTER && !e.ctrlKey){
55940 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55942 } else if(k == e.ESC){
55947 var ecall = { cell : newCell, forward : forward };
55948 this.fireEvent('beforeeditnext', ecall );
55949 newCell = ecall.cell;
55950 forward = ecall.forward;
55954 //Roo.log('next cell after edit');
55955 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
55956 } else if (forward) {
55957 // tabbed past last
55958 this.fireEvent.defer(100, this, ['tabend',this]);
55963 * Ext JS Library 1.1.1
55964 * Copyright(c) 2006-2007, Ext JS, LLC.
55966 * Originally Released Under LGPL - original licence link has changed is not relivant.
55969 * <script type="text/javascript">
55973 * @class Roo.grid.EditorGrid
55974 * @extends Roo.grid.Grid
55975 * Class for creating and editable grid.
55976 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55977 * The container MUST have some type of size defined for the grid to fill. The container will be
55978 * automatically set to position relative if it isn't already.
55979 * @param {Object} dataSource The data model to bind to
55980 * @param {Object} colModel The column model with info about this grid's columns
55982 Roo.grid.EditorGrid = function(container, config){
55983 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
55984 this.getGridEl().addClass("xedit-grid");
55986 if(!this.selModel){
55987 this.selModel = new Roo.grid.CellSelectionModel();
55990 this.activeEditor = null;
55994 * @event beforeedit
55995 * Fires before cell editing is triggered. The edit event object has the following properties <br />
55996 * <ul style="padding:5px;padding-left:16px;">
55997 * <li>grid - This grid</li>
55998 * <li>record - The record being edited</li>
55999 * <li>field - The field name being edited</li>
56000 * <li>value - The value for the field being edited.</li>
56001 * <li>row - The grid row index</li>
56002 * <li>column - The grid column index</li>
56003 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56005 * @param {Object} e An edit event (see above for description)
56007 "beforeedit" : true,
56010 * Fires after a cell is edited. <br />
56011 * <ul style="padding:5px;padding-left:16px;">
56012 * <li>grid - This grid</li>
56013 * <li>record - The record being edited</li>
56014 * <li>field - The field name being edited</li>
56015 * <li>value - The value being set</li>
56016 * <li>originalValue - The original value for the field, before the edit.</li>
56017 * <li>row - The grid row index</li>
56018 * <li>column - The grid column index</li>
56020 * @param {Object} e An edit event (see above for description)
56022 "afteredit" : true,
56024 * @event validateedit
56025 * Fires after a cell is edited, but before the value is set in the record.
56026 * You can use this to modify the value being set in the field, Return false
56027 * to cancel the change. The edit event object has the following properties <br />
56028 * <ul style="padding:5px;padding-left:16px;">
56029 * <li>editor - This editor</li>
56030 * <li>grid - This grid</li>
56031 * <li>record - The record being edited</li>
56032 * <li>field - The field name being edited</li>
56033 * <li>value - The value being set</li>
56034 * <li>originalValue - The original value for the field, before the edit.</li>
56035 * <li>row - The grid row index</li>
56036 * <li>column - The grid column index</li>
56037 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56039 * @param {Object} e An edit event (see above for description)
56041 "validateedit" : true
56043 this.on("bodyscroll", this.stopEditing, this);
56044 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56047 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56049 * @cfg {Number} clicksToEdit
56050 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56057 trackMouseOver: false, // causes very odd FF errors
56059 onCellDblClick : function(g, row, col){
56060 this.startEditing(row, col);
56063 onEditComplete : function(ed, value, startValue){
56064 this.editing = false;
56065 this.activeEditor = null;
56066 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56068 var field = this.colModel.getDataIndex(ed.col);
56073 originalValue: startValue,
56080 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56083 if(String(value) !== String(startValue)){
56085 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56086 r.set(field, e.value);
56087 // if we are dealing with a combo box..
56088 // then we also set the 'name' colum to be the displayField
56089 if (ed.field.displayField && ed.field.name) {
56090 r.set(ed.field.name, ed.field.el.dom.value);
56093 delete e.cancel; //?? why!!!
56094 this.fireEvent("afteredit", e);
56097 this.fireEvent("afteredit", e); // always fire it!
56099 this.view.focusCell(ed.row, ed.col);
56103 * Starts editing the specified for the specified row/column
56104 * @param {Number} rowIndex
56105 * @param {Number} colIndex
56107 startEditing : function(row, col){
56108 this.stopEditing();
56109 if(this.colModel.isCellEditable(col, row)){
56110 this.view.ensureVisible(row, col, true);
56112 var r = this.dataSource.getAt(row);
56113 var field = this.colModel.getDataIndex(col);
56114 var cell = Roo.get(this.view.getCell(row,col));
56119 value: r.data[field],
56124 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56125 this.editing = true;
56126 var ed = this.colModel.getCellEditor(col, row);
56132 ed.render(ed.parentEl || document.body);
56138 (function(){ // complex but required for focus issues in safari, ie and opera
56142 ed.on("complete", this.onEditComplete, this, {single: true});
56143 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56144 this.activeEditor = ed;
56145 var v = r.data[field];
56146 ed.startEdit(this.view.getCell(row, col), v);
56147 // combo's with 'displayField and name set
56148 if (ed.field.displayField && ed.field.name) {
56149 ed.field.el.dom.value = r.data[ed.field.name];
56153 }).defer(50, this);
56159 * Stops any active editing
56161 stopEditing : function(){
56162 if(this.activeEditor){
56163 this.activeEditor.completeEdit();
56165 this.activeEditor = null;
56169 * Called to get grid's drag proxy text, by default returns this.ddText.
56172 getDragDropText : function(){
56173 var count = this.selModel.getSelectedCell() ? 1 : 0;
56174 return String.format(this.ddText, count, count == 1 ? '' : 's');
56179 * Ext JS Library 1.1.1
56180 * Copyright(c) 2006-2007, Ext JS, LLC.
56182 * Originally Released Under LGPL - original licence link has changed is not relivant.
56185 * <script type="text/javascript">
56188 // private - not really -- you end up using it !
56189 // This is a support class used internally by the Grid components
56192 * @class Roo.grid.GridEditor
56193 * @extends Roo.Editor
56194 * Class for creating and editable grid elements.
56195 * @param {Object} config any settings (must include field)
56197 Roo.grid.GridEditor = function(field, config){
56198 if (!config && field.field) {
56200 field = Roo.factory(config.field, Roo.form);
56202 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56203 field.monitorTab = false;
56206 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56209 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56212 alignment: "tl-tl",
56215 cls: "x-small-editor x-grid-editor",
56220 * Ext JS Library 1.1.1
56221 * Copyright(c) 2006-2007, Ext JS, LLC.
56223 * Originally Released Under LGPL - original licence link has changed is not relivant.
56226 * <script type="text/javascript">
56231 Roo.grid.PropertyRecord = Roo.data.Record.create([
56232 {name:'name',type:'string'}, 'value'
56236 Roo.grid.PropertyStore = function(grid, source){
56238 this.store = new Roo.data.Store({
56239 recordType : Roo.grid.PropertyRecord
56241 this.store.on('update', this.onUpdate, this);
56243 this.setSource(source);
56245 Roo.grid.PropertyStore.superclass.constructor.call(this);
56250 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56251 setSource : function(o){
56253 this.store.removeAll();
56256 if(this.isEditableValue(o[k])){
56257 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56260 this.store.loadRecords({records: data}, {}, true);
56263 onUpdate : function(ds, record, type){
56264 if(type == Roo.data.Record.EDIT){
56265 var v = record.data['value'];
56266 var oldValue = record.modified['value'];
56267 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56268 this.source[record.id] = v;
56270 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56277 getProperty : function(row){
56278 return this.store.getAt(row);
56281 isEditableValue: function(val){
56282 if(val && val instanceof Date){
56284 }else if(typeof val == 'object' || typeof val == 'function'){
56290 setValue : function(prop, value){
56291 this.source[prop] = value;
56292 this.store.getById(prop).set('value', value);
56295 getSource : function(){
56296 return this.source;
56300 Roo.grid.PropertyColumnModel = function(grid, store){
56303 g.PropertyColumnModel.superclass.constructor.call(this, [
56304 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56305 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56307 this.store = store;
56308 this.bselect = Roo.DomHelper.append(document.body, {
56309 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56310 {tag: 'option', value: 'true', html: 'true'},
56311 {tag: 'option', value: 'false', html: 'false'}
56314 Roo.id(this.bselect);
56317 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56318 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56319 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56320 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56321 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56323 this.renderCellDelegate = this.renderCell.createDelegate(this);
56324 this.renderPropDelegate = this.renderProp.createDelegate(this);
56327 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56331 valueText : 'Value',
56333 dateFormat : 'm/j/Y',
56336 renderDate : function(dateVal){
56337 return dateVal.dateFormat(this.dateFormat);
56340 renderBool : function(bVal){
56341 return bVal ? 'true' : 'false';
56344 isCellEditable : function(colIndex, rowIndex){
56345 return colIndex == 1;
56348 getRenderer : function(col){
56350 this.renderCellDelegate : this.renderPropDelegate;
56353 renderProp : function(v){
56354 return this.getPropertyName(v);
56357 renderCell : function(val){
56359 if(val instanceof Date){
56360 rv = this.renderDate(val);
56361 }else if(typeof val == 'boolean'){
56362 rv = this.renderBool(val);
56364 return Roo.util.Format.htmlEncode(rv);
56367 getPropertyName : function(name){
56368 var pn = this.grid.propertyNames;
56369 return pn && pn[name] ? pn[name] : name;
56372 getCellEditor : function(colIndex, rowIndex){
56373 var p = this.store.getProperty(rowIndex);
56374 var n = p.data['name'], val = p.data['value'];
56376 if(typeof(this.grid.customEditors[n]) == 'string'){
56377 return this.editors[this.grid.customEditors[n]];
56379 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56380 return this.grid.customEditors[n];
56382 if(val instanceof Date){
56383 return this.editors['date'];
56384 }else if(typeof val == 'number'){
56385 return this.editors['number'];
56386 }else if(typeof val == 'boolean'){
56387 return this.editors['boolean'];
56389 return this.editors['string'];
56395 * @class Roo.grid.PropertyGrid
56396 * @extends Roo.grid.EditorGrid
56397 * This class represents the interface of a component based property grid control.
56398 * <br><br>Usage:<pre><code>
56399 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56407 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56408 * The container MUST have some type of size defined for the grid to fill. The container will be
56409 * automatically set to position relative if it isn't already.
56410 * @param {Object} config A config object that sets properties on this grid.
56412 Roo.grid.PropertyGrid = function(container, config){
56413 config = config || {};
56414 var store = new Roo.grid.PropertyStore(this);
56415 this.store = store;
56416 var cm = new Roo.grid.PropertyColumnModel(this, store);
56417 store.store.sort('name', 'ASC');
56418 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
56421 enableColLock:false,
56422 enableColumnMove:false,
56424 trackMouseOver: false,
56427 this.getGridEl().addClass('x-props-grid');
56428 this.lastEditRow = null;
56429 this.on('columnresize', this.onColumnResize, this);
56432 * @event beforepropertychange
56433 * Fires before a property changes (return false to stop?)
56434 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56435 * @param {String} id Record Id
56436 * @param {String} newval New Value
56437 * @param {String} oldval Old Value
56439 "beforepropertychange": true,
56441 * @event propertychange
56442 * Fires after a property changes
56443 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56444 * @param {String} id Record Id
56445 * @param {String} newval New Value
56446 * @param {String} oldval Old Value
56448 "propertychange": true
56450 this.customEditors = this.customEditors || {};
56452 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
56455 * @cfg {Object} customEditors map of colnames=> custom editors.
56456 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
56457 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
56458 * false disables editing of the field.
56462 * @cfg {Object} propertyNames map of property Names to their displayed value
56465 render : function(){
56466 Roo.grid.PropertyGrid.superclass.render.call(this);
56467 this.autoSize.defer(100, this);
56470 autoSize : function(){
56471 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
56473 this.view.fitColumns();
56477 onColumnResize : function(){
56478 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
56482 * Sets the data for the Grid
56483 * accepts a Key => Value object of all the elements avaiable.
56484 * @param {Object} data to appear in grid.
56486 setSource : function(source){
56487 this.store.setSource(source);
56491 * Gets all the data from the grid.
56492 * @return {Object} data data stored in grid
56494 getSource : function(){
56495 return this.store.getSource();
56504 * @class Roo.grid.Calendar
56505 * @extends Roo.util.Grid
56506 * This class extends the Grid to provide a calendar widget
56507 * <br><br>Usage:<pre><code>
56508 var grid = new Roo.grid.Calendar("my-container-id", {
56511 selModel: mySelectionModel,
56512 autoSizeColumns: true,
56513 monitorWindowResize: false,
56514 trackMouseOver: true
56515 eventstore : real data store..
56521 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56522 * The container MUST have some type of size defined for the grid to fill. The container will be
56523 * automatically set to position relative if it isn't already.
56524 * @param {Object} config A config object that sets properties on this grid.
56526 Roo.grid.Calendar = function(container, config){
56527 // initialize the container
56528 this.container = Roo.get(container);
56529 this.container.update("");
56530 this.container.setStyle("overflow", "hidden");
56531 this.container.addClass('x-grid-container');
56533 this.id = this.container.id;
56535 Roo.apply(this, config);
56536 // check and correct shorthanded configs
56540 for (var r = 0;r < 6;r++) {
56543 for (var c =0;c < 7;c++) {
56547 if (this.eventStore) {
56548 this.eventStore= Roo.factory(this.eventStore, Roo.data);
56549 this.eventStore.on('load',this.onLoad, this);
56550 this.eventStore.on('beforeload',this.clearEvents, this);
56554 this.dataSource = new Roo.data.Store({
56555 proxy: new Roo.data.MemoryProxy(rows),
56556 reader: new Roo.data.ArrayReader({}, [
56557 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
56560 this.dataSource.load();
56561 this.ds = this.dataSource;
56562 this.ds.xmodule = this.xmodule || false;
56565 var cellRender = function(v,x,r)
56567 return String.format(
56568 '<div class="fc-day fc-widget-content"><div>' +
56569 '<div class="fc-event-container"></div>' +
56570 '<div class="fc-day-number">{0}</div>'+
56572 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
56573 '</div></div>', v);
56578 this.colModel = new Roo.grid.ColumnModel( [
56580 xtype: 'ColumnModel',
56582 dataIndex : 'weekday0',
56584 renderer : cellRender
56587 xtype: 'ColumnModel',
56589 dataIndex : 'weekday1',
56591 renderer : cellRender
56594 xtype: 'ColumnModel',
56596 dataIndex : 'weekday2',
56597 header : 'Tuesday',
56598 renderer : cellRender
56601 xtype: 'ColumnModel',
56603 dataIndex : 'weekday3',
56604 header : 'Wednesday',
56605 renderer : cellRender
56608 xtype: 'ColumnModel',
56610 dataIndex : 'weekday4',
56611 header : 'Thursday',
56612 renderer : cellRender
56615 xtype: 'ColumnModel',
56617 dataIndex : 'weekday5',
56619 renderer : cellRender
56622 xtype: 'ColumnModel',
56624 dataIndex : 'weekday6',
56625 header : 'Saturday',
56626 renderer : cellRender
56629 this.cm = this.colModel;
56630 this.cm.xmodule = this.xmodule || false;
56634 //this.selModel = new Roo.grid.CellSelectionModel();
56635 //this.sm = this.selModel;
56636 //this.selModel.init(this);
56640 this.container.setWidth(this.width);
56644 this.container.setHeight(this.height);
56651 * The raw click event for the entire grid.
56652 * @param {Roo.EventObject} e
56657 * The raw dblclick event for the entire grid.
56658 * @param {Roo.EventObject} e
56662 * @event contextmenu
56663 * The raw contextmenu event for the entire grid.
56664 * @param {Roo.EventObject} e
56666 "contextmenu" : true,
56669 * The raw mousedown event for the entire grid.
56670 * @param {Roo.EventObject} e
56672 "mousedown" : true,
56675 * The raw mouseup event for the entire grid.
56676 * @param {Roo.EventObject} e
56681 * The raw mouseover event for the entire grid.
56682 * @param {Roo.EventObject} e
56684 "mouseover" : true,
56687 * The raw mouseout event for the entire grid.
56688 * @param {Roo.EventObject} e
56693 * The raw keypress event for the entire grid.
56694 * @param {Roo.EventObject} e
56699 * The raw keydown event for the entire grid.
56700 * @param {Roo.EventObject} e
56708 * Fires when a cell is clicked
56709 * @param {Grid} this
56710 * @param {Number} rowIndex
56711 * @param {Number} columnIndex
56712 * @param {Roo.EventObject} e
56714 "cellclick" : true,
56716 * @event celldblclick
56717 * Fires when a cell is double clicked
56718 * @param {Grid} this
56719 * @param {Number} rowIndex
56720 * @param {Number} columnIndex
56721 * @param {Roo.EventObject} e
56723 "celldblclick" : true,
56726 * Fires when a row is clicked
56727 * @param {Grid} this
56728 * @param {Number} rowIndex
56729 * @param {Roo.EventObject} e
56733 * @event rowdblclick
56734 * Fires when a row is double clicked
56735 * @param {Grid} this
56736 * @param {Number} rowIndex
56737 * @param {Roo.EventObject} e
56739 "rowdblclick" : true,
56741 * @event headerclick
56742 * Fires when a header is clicked
56743 * @param {Grid} this
56744 * @param {Number} columnIndex
56745 * @param {Roo.EventObject} e
56747 "headerclick" : true,
56749 * @event headerdblclick
56750 * Fires when a header cell is double clicked
56751 * @param {Grid} this
56752 * @param {Number} columnIndex
56753 * @param {Roo.EventObject} e
56755 "headerdblclick" : true,
56757 * @event rowcontextmenu
56758 * Fires when a row is right clicked
56759 * @param {Grid} this
56760 * @param {Number} rowIndex
56761 * @param {Roo.EventObject} e
56763 "rowcontextmenu" : true,
56765 * @event cellcontextmenu
56766 * Fires when a cell is right clicked
56767 * @param {Grid} this
56768 * @param {Number} rowIndex
56769 * @param {Number} cellIndex
56770 * @param {Roo.EventObject} e
56772 "cellcontextmenu" : true,
56774 * @event headercontextmenu
56775 * Fires when a header is right clicked
56776 * @param {Grid} this
56777 * @param {Number} columnIndex
56778 * @param {Roo.EventObject} e
56780 "headercontextmenu" : true,
56782 * @event bodyscroll
56783 * Fires when the body element is scrolled
56784 * @param {Number} scrollLeft
56785 * @param {Number} scrollTop
56787 "bodyscroll" : true,
56789 * @event columnresize
56790 * Fires when the user resizes a column
56791 * @param {Number} columnIndex
56792 * @param {Number} newSize
56794 "columnresize" : true,
56796 * @event columnmove
56797 * Fires when the user moves a column
56798 * @param {Number} oldIndex
56799 * @param {Number} newIndex
56801 "columnmove" : true,
56804 * Fires when row(s) start being dragged
56805 * @param {Grid} this
56806 * @param {Roo.GridDD} dd The drag drop object
56807 * @param {event} e The raw browser event
56809 "startdrag" : true,
56812 * Fires when a drag operation is complete
56813 * @param {Grid} this
56814 * @param {Roo.GridDD} dd The drag drop object
56815 * @param {event} e The raw browser event
56820 * Fires when dragged row(s) are dropped on a valid DD target
56821 * @param {Grid} this
56822 * @param {Roo.GridDD} dd The drag drop object
56823 * @param {String} targetId The target drag drop object
56824 * @param {event} e The raw browser event
56829 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
56830 * @param {Grid} this
56831 * @param {Roo.GridDD} dd The drag drop object
56832 * @param {String} targetId The target drag drop object
56833 * @param {event} e The raw browser event
56838 * Fires when the dragged row(s) first cross another DD target while being dragged
56839 * @param {Grid} this
56840 * @param {Roo.GridDD} dd The drag drop object
56841 * @param {String} targetId The target drag drop object
56842 * @param {event} e The raw browser event
56844 "dragenter" : true,
56847 * Fires when the dragged row(s) leave another DD target while being dragged
56848 * @param {Grid} this
56849 * @param {Roo.GridDD} dd The drag drop object
56850 * @param {String} targetId The target drag drop object
56851 * @param {event} e The raw browser event
56856 * Fires when a row is rendered, so you can change add a style to it.
56857 * @param {GridView} gridview The grid view
56858 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
56864 * Fires when the grid is rendered
56865 * @param {Grid} grid
56870 * Fires when a date is selected
56871 * @param {DatePicker} this
56872 * @param {Date} date The selected date
56876 * @event monthchange
56877 * Fires when the displayed month changes
56878 * @param {DatePicker} this
56879 * @param {Date} date The selected month
56881 'monthchange': true,
56883 * @event evententer
56884 * Fires when mouse over an event
56885 * @param {Calendar} this
56886 * @param {event} Event
56888 'evententer': true,
56890 * @event eventleave
56891 * Fires when the mouse leaves an
56892 * @param {Calendar} this
56895 'eventleave': true,
56897 * @event eventclick
56898 * Fires when the mouse click an
56899 * @param {Calendar} this
56902 'eventclick': true,
56904 * @event eventrender
56905 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
56906 * @param {Calendar} this
56907 * @param {data} data to be modified
56909 'eventrender': true
56913 Roo.grid.Grid.superclass.constructor.call(this);
56914 this.on('render', function() {
56915 this.view.el.addClass('x-grid-cal');
56917 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
56921 if (!Roo.grid.Calendar.style) {
56922 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
56925 '.x-grid-cal .x-grid-col' : {
56926 height: 'auto !important',
56927 'vertical-align': 'top'
56929 '.x-grid-cal .fc-event-hori' : {
56940 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
56942 * @cfg {Store} eventStore The store that loads events.
56947 activeDate : false,
56950 monitorWindowResize : false,
56953 resizeColumns : function() {
56954 var col = (this.view.el.getWidth() / 7) - 3;
56955 // loop through cols, and setWidth
56956 for(var i =0 ; i < 7 ; i++){
56957 this.cm.setColumnWidth(i, col);
56960 setDate :function(date) {
56962 Roo.log('setDate?');
56964 this.resizeColumns();
56965 var vd = this.activeDate;
56966 this.activeDate = date;
56967 // if(vd && this.el){
56968 // var t = date.getTime();
56969 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
56970 // Roo.log('using add remove');
56972 // this.fireEvent('monthchange', this, date);
56974 // this.cells.removeClass("fc-state-highlight");
56975 // this.cells.each(function(c){
56976 // if(c.dateValue == t){
56977 // c.addClass("fc-state-highlight");
56978 // setTimeout(function(){
56979 // try{c.dom.firstChild.focus();}catch(e){}
56989 var days = date.getDaysInMonth();
56991 var firstOfMonth = date.getFirstDateOfMonth();
56992 var startingPos = firstOfMonth.getDay()-this.startDay;
56994 if(startingPos < this.startDay){
56998 var pm = date.add(Date.MONTH, -1);
56999 var prevStart = pm.getDaysInMonth()-startingPos;
57003 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57005 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57006 //this.cells.addClassOnOver('fc-state-hover');
57008 var cells = this.cells.elements;
57009 var textEls = this.textNodes;
57011 //Roo.each(cells, function(cell){
57012 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57015 days += startingPos;
57017 // convert everything to numbers so it's fast
57018 var day = 86400000;
57019 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57022 //Roo.log(prevStart);
57024 var today = new Date().clearTime().getTime();
57025 var sel = date.clearTime().getTime();
57026 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57027 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57028 var ddMatch = this.disabledDatesRE;
57029 var ddText = this.disabledDatesText;
57030 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57031 var ddaysText = this.disabledDaysText;
57032 var format = this.format;
57034 var setCellClass = function(cal, cell){
57036 //Roo.log('set Cell Class');
57038 var t = d.getTime();
57043 cell.dateValue = t;
57045 cell.className += " fc-today";
57046 cell.className += " fc-state-highlight";
57047 cell.title = cal.todayText;
57050 // disable highlight in other month..
57051 cell.className += " fc-state-highlight";
57056 //cell.className = " fc-state-disabled";
57057 cell.title = cal.minText;
57061 //cell.className = " fc-state-disabled";
57062 cell.title = cal.maxText;
57066 if(ddays.indexOf(d.getDay()) != -1){
57067 // cell.title = ddaysText;
57068 // cell.className = " fc-state-disabled";
57071 if(ddMatch && format){
57072 var fvalue = d.dateFormat(format);
57073 if(ddMatch.test(fvalue)){
57074 cell.title = ddText.replace("%0", fvalue);
57075 cell.className = " fc-state-disabled";
57079 if (!cell.initialClassName) {
57080 cell.initialClassName = cell.dom.className;
57083 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57088 for(; i < startingPos; i++) {
57089 cells[i].dayName = (++prevStart);
57090 Roo.log(textEls[i]);
57091 d.setDate(d.getDate()+1);
57093 //cells[i].className = "fc-past fc-other-month";
57094 setCellClass(this, cells[i]);
57099 for(; i < days; i++){
57100 intDay = i - startingPos + 1;
57101 cells[i].dayName = (intDay);
57102 d.setDate(d.getDate()+1);
57104 cells[i].className = ''; // "x-date-active";
57105 setCellClass(this, cells[i]);
57109 for(; i < 42; i++) {
57110 //textEls[i].innerHTML = (++extraDays);
57112 d.setDate(d.getDate()+1);
57113 cells[i].dayName = (++extraDays);
57114 cells[i].className = "fc-future fc-other-month";
57115 setCellClass(this, cells[i]);
57118 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57120 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57122 // this will cause all the cells to mis
57125 for (var r = 0;r < 6;r++) {
57126 for (var c =0;c < 7;c++) {
57127 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57131 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57132 for(i=0;i<cells.length;i++) {
57134 this.cells.elements[i].dayName = cells[i].dayName ;
57135 this.cells.elements[i].className = cells[i].className;
57136 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57137 this.cells.elements[i].title = cells[i].title ;
57138 this.cells.elements[i].dateValue = cells[i].dateValue ;
57144 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57145 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57147 ////if(totalRows != 6){
57148 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57149 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57152 this.fireEvent('monthchange', this, date);
57157 * Returns the grid's SelectionModel.
57158 * @return {SelectionModel}
57160 getSelectionModel : function(){
57161 if(!this.selModel){
57162 this.selModel = new Roo.grid.CellSelectionModel();
57164 return this.selModel;
57168 this.eventStore.load()
57174 findCell : function(dt) {
57175 dt = dt.clearTime().getTime();
57177 this.cells.each(function(c){
57178 //Roo.log("check " +c.dateValue + '?=' + dt);
57179 if(c.dateValue == dt){
57189 findCells : function(rec) {
57190 var s = rec.data.start_dt.clone().clearTime().getTime();
57192 var e= rec.data.end_dt.clone().clearTime().getTime();
57195 this.cells.each(function(c){
57196 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57198 if(c.dateValue > e){
57201 if(c.dateValue < s){
57210 findBestRow: function(cells)
57214 for (var i =0 ; i < cells.length;i++) {
57215 ret = Math.max(cells[i].rows || 0,ret);
57222 addItem : function(rec)
57224 // look for vertical location slot in
57225 var cells = this.findCells(rec);
57227 rec.row = this.findBestRow(cells);
57229 // work out the location.
57233 for(var i =0; i < cells.length; i++) {
57241 if (crow.start.getY() == cells[i].getY()) {
57243 crow.end = cells[i];
57259 for (var i = 0; i < cells.length;i++) {
57260 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57267 clearEvents: function() {
57269 if (!this.eventStore.getCount()) {
57272 // reset number of rows in cells.
57273 Roo.each(this.cells.elements, function(c){
57277 this.eventStore.each(function(e) {
57278 this.clearEvent(e);
57283 clearEvent : function(ev)
57286 Roo.each(ev.els, function(el) {
57287 el.un('mouseenter' ,this.onEventEnter, this);
57288 el.un('mouseleave' ,this.onEventLeave, this);
57296 renderEvent : function(ev,ctr) {
57298 ctr = this.view.el.select('.fc-event-container',true).first();
57302 this.clearEvent(ev);
57308 var cells = ev.cells;
57309 var rows = ev.rows;
57310 this.fireEvent('eventrender', this, ev);
57312 for(var i =0; i < rows.length; i++) {
57316 cls += ' fc-event-start';
57318 if ((i+1) == rows.length) {
57319 cls += ' fc-event-end';
57322 //Roo.log(ev.data);
57323 // how many rows should it span..
57324 var cg = this.eventTmpl.append(ctr,Roo.apply({
57327 }, ev.data) , true);
57330 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57331 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57332 cg.on('click', this.onEventClick, this, ev);
57336 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57337 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57340 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57341 cg.setWidth(ebox.right - sbox.x -2);
57345 renderEvents: function()
57347 // first make sure there is enough space..
57349 if (!this.eventTmpl) {
57350 this.eventTmpl = new Roo.Template(
57351 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57352 '<div class="fc-event-inner">' +
57353 '<span class="fc-event-time">{time}</span>' +
57354 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57356 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57364 this.cells.each(function(c) {
57365 //Roo.log(c.select('.fc-day-content div',true).first());
57366 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57369 var ctr = this.view.el.select('.fc-event-container',true).first();
57372 this.eventStore.each(function(ev){
57374 this.renderEvent(ev);
57378 this.view.layout();
57382 onEventEnter: function (e, el,event,d) {
57383 this.fireEvent('evententer', this, el, event);
57386 onEventLeave: function (e, el,event,d) {
57387 this.fireEvent('eventleave', this, el, event);
57390 onEventClick: function (e, el,event,d) {
57391 this.fireEvent('eventclick', this, el, event);
57394 onMonthChange: function () {
57398 onLoad: function () {
57400 //Roo.log('calendar onload');
57402 if(this.eventStore.getCount() > 0){
57406 this.eventStore.each(function(d){
57411 if (typeof(add.end_dt) == 'undefined') {
57412 Roo.log("Missing End time in calendar data: ");
57416 if (typeof(add.start_dt) == 'undefined') {
57417 Roo.log("Missing Start time in calendar data: ");
57421 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
57422 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
57423 add.id = add.id || d.id;
57424 add.title = add.title || '??';
57432 this.renderEvents();
57442 render : function ()
57446 if (!this.view.el.hasClass('course-timesheet')) {
57447 this.view.el.addClass('course-timesheet');
57449 if (this.tsStyle) {
57454 Roo.log(_this.grid.view.el.getWidth());
57457 this.tsStyle = Roo.util.CSS.createStyleSheet({
57458 '.course-timesheet .x-grid-row' : {
57461 '.x-grid-row td' : {
57462 'vertical-align' : 0
57464 '.course-edit-link' : {
57466 'text-overflow' : 'ellipsis',
57467 'overflow' : 'hidden',
57468 'white-space' : 'nowrap',
57469 'cursor' : 'pointer'
57474 '.de-act-sup-link' : {
57475 'color' : 'purple',
57476 'text-decoration' : 'line-through'
57480 'text-decoration' : 'line-through'
57482 '.course-timesheet .course-highlight' : {
57483 'border-top-style': 'dashed !important',
57484 'border-bottom-bottom': 'dashed !important'
57486 '.course-timesheet .course-item' : {
57487 'font-family' : 'tahoma, arial, helvetica',
57488 'font-size' : '11px',
57489 'overflow' : 'hidden',
57490 'padding-left' : '10px',
57491 'padding-right' : '10px',
57492 'padding-top' : '10px'
57500 monitorWindowResize : false,
57501 cellrenderer : function(v,x,r)
57506 xtype: 'CellSelectionModel',
57513 beforeload : function (_self, options)
57515 options.params = options.params || {};
57516 options.params._month = _this.monthField.getValue();
57517 options.params.limit = 9999;
57518 options.params['sort'] = 'when_dt';
57519 options.params['dir'] = 'ASC';
57520 this.proxy.loadResponse = this.loadResponse;
57522 //this.addColumns();
57524 load : function (_self, records, options)
57526 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
57527 // if you click on the translation.. you can edit it...
57528 var el = Roo.get(this);
57529 var id = el.dom.getAttribute('data-id');
57530 var d = el.dom.getAttribute('data-date');
57531 var t = el.dom.getAttribute('data-time');
57532 //var id = this.child('span').dom.textContent;
57535 Pman.Dialog.CourseCalendar.show({
57539 productitem_active : id ? 1 : 0
57541 _this.grid.ds.load({});
57546 _this.panel.fireEvent('resize', [ '', '' ]);
57549 loadResponse : function(o, success, response){
57550 // this is overridden on before load..
57552 Roo.log("our code?");
57553 //Roo.log(success);
57554 //Roo.log(response)
57555 delete this.activeRequest;
57557 this.fireEvent("loadexception", this, o, response);
57558 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57563 result = o.reader.read(response);
57565 Roo.log("load exception?");
57566 this.fireEvent("loadexception", this, o, response, e);
57567 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57570 Roo.log("ready...");
57571 // loop through result.records;
57572 // and set this.tdate[date] = [] << array of records..
57574 Roo.each(result.records, function(r){
57576 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
57577 _this.tdata[r.data.when_dt.format('j')] = [];
57579 _this.tdata[r.data.when_dt.format('j')].push(r.data);
57582 //Roo.log(_this.tdata);
57584 result.records = [];
57585 result.totalRecords = 6;
57587 // let's generate some duumy records for the rows.
57588 //var st = _this.dateField.getValue();
57590 // work out monday..
57591 //st = st.add(Date.DAY, -1 * st.format('w'));
57593 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57595 var firstOfMonth = date.getFirstDayOfMonth();
57596 var days = date.getDaysInMonth();
57598 var firstAdded = false;
57599 for (var i = 0; i < result.totalRecords ; i++) {
57600 //var d= st.add(Date.DAY, i);
57603 for(var w = 0 ; w < 7 ; w++){
57604 if(!firstAdded && firstOfMonth != w){
57611 var dd = (d > 0 && d < 10) ? "0"+d : d;
57612 row['weekday'+w] = String.format(
57613 '<span style="font-size: 16px;"><b>{0}</b></span>'+
57614 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
57616 date.format('Y-m-')+dd
57619 if(typeof(_this.tdata[d]) != 'undefined'){
57620 Roo.each(_this.tdata[d], function(r){
57624 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
57625 if(r.parent_id*1>0){
57626 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
57629 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
57630 deactive = 'de-act-link';
57633 row['weekday'+w] += String.format(
57634 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
57636 r.product_id_name, //1
57637 r.when_dt.format('h:ia'), //2
57647 // only do this if something added..
57649 result.records.push(_this.grid.dataSource.reader.newRow(row));
57653 // push it twice. (second one with an hour..
57657 this.fireEvent("load", this, o, o.request.arg);
57658 o.request.callback.call(o.request.scope, result, o.request.arg, true);
57660 sortInfo : {field: 'when_dt', direction : 'ASC' },
57662 xtype: 'HttpProxy',
57665 url : baseURL + '/Roo/Shop_course.php'
57668 xtype: 'JsonReader',
57685 'name': 'parent_id',
57689 'name': 'product_id',
57693 'name': 'productitem_id',
57711 click : function (_self, e)
57713 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57714 sd.setMonth(sd.getMonth()-1);
57715 _this.monthField.setValue(sd.format('Y-m-d'));
57716 _this.grid.ds.load({});
57722 xtype: 'Separator',
57726 xtype: 'MonthField',
57729 render : function (_self)
57731 _this.monthField = _self;
57732 // _this.monthField.set today
57734 select : function (combo, date)
57736 _this.grid.ds.load({});
57739 value : (function() { return new Date(); })()
57742 xtype: 'Separator',
57748 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
57758 click : function (_self, e)
57760 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57761 sd.setMonth(sd.getMonth()+1);
57762 _this.monthField.setValue(sd.format('Y-m-d'));
57763 _this.grid.ds.load({});
57776 * Ext JS Library 1.1.1
57777 * Copyright(c) 2006-2007, Ext JS, LLC.
57779 * Originally Released Under LGPL - original licence link has changed is not relivant.
57782 * <script type="text/javascript">
57786 * @class Roo.LoadMask
57787 * A simple utility class for generically masking elements while loading data. If the element being masked has
57788 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
57789 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
57790 * element's UpdateManager load indicator and will be destroyed after the initial load.
57792 * Create a new LoadMask
57793 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
57794 * @param {Object} config The config object
57796 Roo.LoadMask = function(el, config){
57797 this.el = Roo.get(el);
57798 Roo.apply(this, config);
57800 this.store.on('beforeload', this.onBeforeLoad, this);
57801 this.store.on('load', this.onLoad, this);
57802 this.store.on('loadexception', this.onLoadException, this);
57803 this.removeMask = false;
57805 var um = this.el.getUpdateManager();
57806 um.showLoadIndicator = false; // disable the default indicator
57807 um.on('beforeupdate', this.onBeforeLoad, this);
57808 um.on('update', this.onLoad, this);
57809 um.on('failure', this.onLoad, this);
57810 this.removeMask = true;
57814 Roo.LoadMask.prototype = {
57816 * @cfg {Boolean} removeMask
57817 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
57818 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
57821 * @cfg {String} msg
57822 * The text to display in a centered loading message box (defaults to 'Loading...')
57824 msg : 'Loading...',
57826 * @cfg {String} msgCls
57827 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
57829 msgCls : 'x-mask-loading',
57832 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
57838 * Disables the mask to prevent it from being displayed
57840 disable : function(){
57841 this.disabled = true;
57845 * Enables the mask so that it can be displayed
57847 enable : function(){
57848 this.disabled = false;
57851 onLoadException : function()
57853 Roo.log(arguments);
57855 if (typeof(arguments[3]) != 'undefined') {
57856 Roo.MessageBox.alert("Error loading",arguments[3]);
57860 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
57861 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
57870 this.el.unmask(this.removeMask);
57873 onLoad : function()
57875 this.el.unmask(this.removeMask);
57879 onBeforeLoad : function(){
57880 if(!this.disabled){
57881 this.el.mask(this.msg, this.msgCls);
57886 destroy : function(){
57888 this.store.un('beforeload', this.onBeforeLoad, this);
57889 this.store.un('load', this.onLoad, this);
57890 this.store.un('loadexception', this.onLoadException, this);
57892 var um = this.el.getUpdateManager();
57893 um.un('beforeupdate', this.onBeforeLoad, this);
57894 um.un('update', this.onLoad, this);
57895 um.un('failure', this.onLoad, this);
57900 * Ext JS Library 1.1.1
57901 * Copyright(c) 2006-2007, Ext JS, LLC.
57903 * Originally Released Under LGPL - original licence link has changed is not relivant.
57906 * <script type="text/javascript">
57911 * @class Roo.XTemplate
57912 * @extends Roo.Template
57913 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
57915 var t = new Roo.XTemplate(
57916 '<select name="{name}">',
57917 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
57921 // then append, applying the master template values
57924 * Supported features:
57929 {a_variable} - output encoded.
57930 {a_variable.format:("Y-m-d")} - call a method on the variable
57931 {a_variable:raw} - unencoded output
57932 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
57933 {a_variable:this.method_on_template(...)} - call a method on the template object.
57938 <tpl for="a_variable or condition.."></tpl>
57939 <tpl if="a_variable or condition"></tpl>
57940 <tpl exec="some javascript"></tpl>
57941 <tpl name="named_template"></tpl> (experimental)
57943 <tpl for="."></tpl> - just iterate the property..
57944 <tpl for=".."></tpl> - iterates with the parent (probably the template)
57948 Roo.XTemplate = function()
57950 Roo.XTemplate.superclass.constructor.apply(this, arguments);
57957 Roo.extend(Roo.XTemplate, Roo.Template, {
57960 * The various sub templates
57965 * basic tag replacing syntax
57968 * // you can fake an object call by doing this
57972 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
57975 * compile the template
57977 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
57980 compile: function()
57984 s = ['<tpl>', s, '</tpl>'].join('');
57986 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
57987 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
57988 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
57989 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
57990 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
57995 while(true == !!(m = s.match(re))){
57996 var forMatch = m[0].match(nameRe),
57997 ifMatch = m[0].match(ifRe),
57998 execMatch = m[0].match(execRe),
57999 namedMatch = m[0].match(namedRe),
58004 name = forMatch && forMatch[1] ? forMatch[1] : '';
58007 // if - puts fn into test..
58008 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58010 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58015 // exec - calls a function... returns empty if true is returned.
58016 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58018 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58026 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58027 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58028 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58031 var uid = namedMatch ? namedMatch[1] : id;
58035 id: namedMatch ? namedMatch[1] : id,
58042 s = s.replace(m[0], '');
58044 s = s.replace(m[0], '{xtpl'+ id + '}');
58049 for(var i = tpls.length-1; i >= 0; --i){
58050 this.compileTpl(tpls[i]);
58051 this.tpls[tpls[i].id] = tpls[i];
58053 this.master = tpls[tpls.length-1];
58057 * same as applyTemplate, except it's done to one of the subTemplates
58058 * when using named templates, you can do:
58060 * var str = pl.applySubTemplate('your-name', values);
58063 * @param {Number} id of the template
58064 * @param {Object} values to apply to template
58065 * @param {Object} parent (normaly the instance of this object)
58067 applySubTemplate : function(id, values, parent)
58071 var t = this.tpls[id];
58075 if(t.test && !t.test.call(this, values, parent)){
58079 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58080 Roo.log(e.toString());
58086 if(t.exec && t.exec.call(this, values, parent)){
58090 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58091 Roo.log(e.toString());
58096 var vs = t.target ? t.target.call(this, values, parent) : values;
58097 parent = t.target ? values : parent;
58098 if(t.target && vs instanceof Array){
58100 for(var i = 0, len = vs.length; i < len; i++){
58101 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58103 return buf.join('');
58105 return t.compiled.call(this, vs, parent);
58107 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58108 Roo.log(e.toString());
58109 Roo.log(t.compiled);
58114 compileTpl : function(tpl)
58116 var fm = Roo.util.Format;
58117 var useF = this.disableFormats !== true;
58118 var sep = Roo.isGecko ? "+" : ",";
58119 var undef = function(str) {
58120 Roo.log("Property not found :" + str);
58124 var fn = function(m, name, format, args)
58126 //Roo.log(arguments);
58127 args = args ? args.replace(/\\'/g,"'") : args;
58128 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58129 if (typeof(format) == 'undefined') {
58130 format= 'htmlEncode';
58132 if (format == 'raw' ) {
58136 if(name.substr(0, 4) == 'xtpl'){
58137 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58140 // build an array of options to determine if value is undefined..
58142 // basically get 'xxxx.yyyy' then do
58143 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58144 // (function () { Roo.log("Property not found"); return ''; })() :
58149 Roo.each(name.split('.'), function(st) {
58150 lookfor += (lookfor.length ? '.': '') + st;
58151 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58154 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58157 if(format && useF){
58159 args = args ? ',' + args : "";
58161 if(format.substr(0, 5) != "this."){
58162 format = "fm." + format + '(';
58164 format = 'this.call("'+ format.substr(5) + '", ';
58168 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58172 // called with xxyx.yuu:(test,test)
58174 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58176 // raw.. - :raw modifier..
58177 return "'"+ sep + udef_st + name + ")"+sep+"'";
58181 // branched to use + in gecko and [].join() in others
58183 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58184 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58187 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58188 body.push(tpl.body.replace(/(\r\n|\n)/g,
58189 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58190 body.push("'].join('');};};");
58191 body = body.join('');
58194 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58196 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58202 applyTemplate : function(values){
58203 return this.master.compiled.call(this, values, {});
58204 //var s = this.subs;
58207 apply : function(){
58208 return this.applyTemplate.apply(this, arguments);
58213 Roo.XTemplate.from = function(el){
58214 el = Roo.getDom(el);
58215 return new Roo.XTemplate(el.value || el.innerHTML);