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.bootstrap.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;
6053 var fireDocReady = function(){
6055 docReadyState = true;
6058 clearInterval(docReadyProcId);
6060 if(Roo.isGecko || Roo.isOpera) {
6061 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6064 var defer = document.getElementById("ie-deferred-loader");
6066 defer.onreadystatechange = null;
6067 defer.parentNode.removeChild(defer);
6071 docReadyEvent.fire();
6072 docReadyEvent.clearListeners();
6077 var initDocReady = function(){
6078 docReadyEvent = new Roo.util.Event();
6079 if(Roo.isGecko || Roo.isOpera) {
6080 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6082 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6083 var defer = document.getElementById("ie-deferred-loader");
6084 defer.onreadystatechange = function(){
6085 if(this.readyState == "complete"){
6089 }else if(Roo.isSafari){
6090 docReadyProcId = setInterval(function(){
6091 var rs = document.readyState;
6092 if(rs == "complete") {
6097 // no matter what, make sure it fires on load
6098 E.on(window, "load", fireDocReady);
6101 var createBuffered = function(h, o){
6102 var task = new Roo.util.DelayedTask(h);
6104 // create new event object impl so new events don't wipe out properties
6105 e = new Roo.EventObjectImpl(e);
6106 task.delay(o.buffer, h, null, [e]);
6110 var createSingle = function(h, el, ename, fn){
6112 Roo.EventManager.removeListener(el, ename, fn);
6117 var createDelayed = function(h, o){
6119 // create new event object impl so new events don't wipe out properties
6120 e = new Roo.EventObjectImpl(e);
6121 setTimeout(function(){
6126 var transitionEndVal = false;
6128 var transitionEnd = function()
6130 if (transitionEndVal) {
6131 return transitionEndVal;
6133 var el = document.createElement('div');
6135 var transEndEventNames = {
6136 WebkitTransition : 'webkitTransitionEnd',
6137 MozTransition : 'transitionend',
6138 OTransition : 'oTransitionEnd otransitionend',
6139 transition : 'transitionend'
6142 for (var name in transEndEventNames) {
6143 if (el.style[name] !== undefined) {
6144 transitionEndVal = transEndEventNames[name];
6145 return transitionEndVal ;
6151 var listen = function(element, ename, opt, fn, scope){
6152 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6153 fn = fn || o.fn; scope = scope || o.scope;
6154 var el = Roo.getDom(element);
6158 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6161 if (ename == 'transitionend') {
6162 ename = transitionEnd();
6164 var h = function(e){
6165 e = Roo.EventObject.setEvent(e);
6168 t = e.getTarget(o.delegate, el);
6175 if(o.stopEvent === true){
6178 if(o.preventDefault === true){
6181 if(o.stopPropagation === true){
6182 e.stopPropagation();
6185 if(o.normalized === false){
6189 fn.call(scope || el, e, t, o);
6192 h = createDelayed(h, o);
6195 h = createSingle(h, el, ename, fn);
6198 h = createBuffered(h, o);
6200 fn._handlers = fn._handlers || [];
6203 fn._handlers.push([Roo.id(el), ename, h]);
6208 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6209 el.addEventListener("DOMMouseScroll", h, false);
6210 E.on(window, 'unload', function(){
6211 el.removeEventListener("DOMMouseScroll", h, false);
6214 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6215 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6220 var stopListening = function(el, ename, fn){
6221 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6223 for(var i = 0, len = hds.length; i < len; i++){
6225 if(h[0] == id && h[1] == ename){
6232 E.un(el, ename, hd);
6233 el = Roo.getDom(el);
6234 if(ename == "mousewheel" && el.addEventListener){
6235 el.removeEventListener("DOMMouseScroll", hd, false);
6237 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6238 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6242 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6249 * @scope Roo.EventManager
6254 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6255 * object with a Roo.EventObject
6256 * @param {Function} fn The method the event invokes
6257 * @param {Object} scope An object that becomes the scope of the handler
6258 * @param {boolean} override If true, the obj passed in becomes
6259 * the execution scope of the listener
6260 * @return {Function} The wrapped function
6263 wrap : function(fn, scope, override){
6265 Roo.EventObject.setEvent(e);
6266 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6271 * Appends an event handler to an element (shorthand for addListener)
6272 * @param {String/HTMLElement} element The html element or id to assign the
6273 * @param {String} eventName The type of event to listen for
6274 * @param {Function} handler The method the event invokes
6275 * @param {Object} scope (optional) The scope in which to execute the handler
6276 * function. The handler function's "this" context.
6277 * @param {Object} options (optional) An object containing handler configuration
6278 * properties. This may contain any of the following properties:<ul>
6279 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6280 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6281 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6282 * <li>preventDefault {Boolean} True to prevent the default action</li>
6283 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6284 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6285 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6286 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6287 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6288 * by the specified number of milliseconds. If the event fires again within that time, the original
6289 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6292 * <b>Combining Options</b><br>
6293 * Using the options argument, it is possible to combine different types of listeners:<br>
6295 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6297 el.on('click', this.onClick, this, {
6304 * <b>Attaching multiple handlers in 1 call</b><br>
6305 * The method also allows for a single argument to be passed which is a config object containing properties
6306 * which specify multiple handlers.
6316 fn: this.onMouseOver
6325 * Or a shorthand syntax:<br>
6328 'click' : this.onClick,
6329 'mouseover' : this.onMouseOver,
6330 'mouseout' : this.onMouseOut
6334 addListener : function(element, eventName, fn, scope, options){
6335 if(typeof eventName == "object"){
6341 if(typeof o[e] == "function"){
6343 listen(element, e, o, o[e], o.scope);
6345 // individual options
6346 listen(element, e, o[e]);
6351 return listen(element, eventName, options, fn, scope);
6355 * Removes an event handler
6357 * @param {String/HTMLElement} element The id or html element to remove the
6359 * @param {String} eventName The type of event
6360 * @param {Function} fn
6361 * @return {Boolean} True if a listener was actually removed
6363 removeListener : function(element, eventName, fn){
6364 return stopListening(element, eventName, fn);
6368 * Fires when the document is ready (before onload and before images are loaded). Can be
6369 * accessed shorthanded Roo.onReady().
6370 * @param {Function} fn The method the event invokes
6371 * @param {Object} scope An object that becomes the scope of the handler
6372 * @param {boolean} options
6374 onDocumentReady : function(fn, scope, options){
6375 if(docReadyState){ // if it already fired
6376 docReadyEvent.addListener(fn, scope, options);
6377 docReadyEvent.fire();
6378 docReadyEvent.clearListeners();
6384 docReadyEvent.addListener(fn, scope, options);
6388 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6389 * @param {Function} fn The method the event invokes
6390 * @param {Object} scope An object that becomes the scope of the handler
6391 * @param {boolean} options
6393 onWindowResize : function(fn, scope, options){
6395 resizeEvent = new Roo.util.Event();
6396 resizeTask = new Roo.util.DelayedTask(function(){
6397 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6399 E.on(window, "resize", function(){
6401 resizeTask.delay(50);
6403 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6407 resizeEvent.addListener(fn, scope, options);
6411 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6412 * @param {Function} fn The method the event invokes
6413 * @param {Object} scope An object that becomes the scope of the handler
6414 * @param {boolean} options
6416 onTextResize : function(fn, scope, options){
6418 textEvent = new Roo.util.Event();
6419 var textEl = new Roo.Element(document.createElement('div'));
6420 textEl.dom.className = 'x-text-resize';
6421 textEl.dom.innerHTML = 'X';
6422 textEl.appendTo(document.body);
6423 textSize = textEl.dom.offsetHeight;
6424 setInterval(function(){
6425 if(textEl.dom.offsetHeight != textSize){
6426 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6428 }, this.textResizeInterval);
6430 textEvent.addListener(fn, scope, options);
6434 * Removes the passed window resize listener.
6435 * @param {Function} fn The method the event invokes
6436 * @param {Object} scope The scope of handler
6438 removeResizeListener : function(fn, scope){
6440 resizeEvent.removeListener(fn, scope);
6445 fireResize : function(){
6447 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6451 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6455 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6457 textResizeInterval : 50
6462 * @scopeAlias pub=Roo.EventManager
6466 * Appends an event handler to an element (shorthand for addListener)
6467 * @param {String/HTMLElement} element The html element or id to assign the
6468 * @param {String} eventName The type of event to listen for
6469 * @param {Function} handler The method the event invokes
6470 * @param {Object} scope (optional) The scope in which to execute the handler
6471 * function. The handler function's "this" context.
6472 * @param {Object} options (optional) An object containing handler configuration
6473 * properties. This may contain any of the following properties:<ul>
6474 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6475 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6476 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6477 * <li>preventDefault {Boolean} True to prevent the default action</li>
6478 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6479 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6480 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6481 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6482 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6483 * by the specified number of milliseconds. If the event fires again within that time, the original
6484 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6487 * <b>Combining Options</b><br>
6488 * Using the options argument, it is possible to combine different types of listeners:<br>
6490 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6492 el.on('click', this.onClick, this, {
6499 * <b>Attaching multiple handlers in 1 call</b><br>
6500 * The method also allows for a single argument to be passed which is a config object containing properties
6501 * which specify multiple handlers.
6511 fn: this.onMouseOver
6520 * Or a shorthand syntax:<br>
6523 'click' : this.onClick,
6524 'mouseover' : this.onMouseOver,
6525 'mouseout' : this.onMouseOut
6529 pub.on = pub.addListener;
6530 pub.un = pub.removeListener;
6532 pub.stoppedMouseDownEvent = new Roo.util.Event();
6536 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6537 * @param {Function} fn The method the event invokes
6538 * @param {Object} scope An object that becomes the scope of the handler
6539 * @param {boolean} override If true, the obj passed in becomes
6540 * the execution scope of the listener
6544 Roo.onReady = Roo.EventManager.onDocumentReady;
6546 Roo.onReady(function(){
6547 var bd = Roo.get(document.body);
6552 : Roo.isGecko ? "roo-gecko"
6553 : Roo.isOpera ? "roo-opera"
6554 : Roo.isSafari ? "roo-safari" : ""];
6557 cls.push("roo-mac");
6560 cls.push("roo-linux");
6562 if(Roo.isBorderBox){
6563 cls.push('roo-border-box');
6565 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6566 var p = bd.dom.parentNode;
6568 p.className += ' roo-strict';
6571 bd.addClass(cls.join(' '));
6575 * @class Roo.EventObject
6576 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6577 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6580 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6582 var target = e.getTarget();
6585 var myDiv = Roo.get("myDiv");
6586 myDiv.on("click", handleClick);
6588 Roo.EventManager.on("myDiv", 'click', handleClick);
6589 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6593 Roo.EventObject = function(){
6595 var E = Roo.lib.Event;
6597 // safari keypress events for special keys return bad keycodes
6600 63235 : 39, // right
6603 63276 : 33, // page up
6604 63277 : 34, // page down
6605 63272 : 46, // delete
6610 // normalize button clicks
6611 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6612 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6614 Roo.EventObjectImpl = function(e){
6616 this.setEvent(e.browserEvent || e);
6619 Roo.EventObjectImpl.prototype = {
6621 * Used to fix doc tools.
6622 * @scope Roo.EventObject.prototype
6628 /** The normal browser event */
6629 browserEvent : null,
6630 /** The button pressed in a mouse event */
6632 /** True if the shift key was down during the event */
6634 /** True if the control key was down during the event */
6636 /** True if the alt key was down during the event */
6695 setEvent : function(e){
6696 if(e == this || (e && e.browserEvent)){ // already wrapped
6699 this.browserEvent = e;
6701 // normalize buttons
6702 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6703 if(e.type == 'click' && this.button == -1){
6707 this.shiftKey = e.shiftKey;
6708 // mac metaKey behaves like ctrlKey
6709 this.ctrlKey = e.ctrlKey || e.metaKey;
6710 this.altKey = e.altKey;
6711 // in getKey these will be normalized for the mac
6712 this.keyCode = e.keyCode;
6713 // keyup warnings on firefox.
6714 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6715 // cache the target for the delayed and or buffered events
6716 this.target = E.getTarget(e);
6718 this.xy = E.getXY(e);
6721 this.shiftKey = false;
6722 this.ctrlKey = false;
6723 this.altKey = false;
6733 * Stop the event (preventDefault and stopPropagation)
6735 stopEvent : function(){
6736 if(this.browserEvent){
6737 if(this.browserEvent.type == 'mousedown'){
6738 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6740 E.stopEvent(this.browserEvent);
6745 * Prevents the browsers default handling of the event.
6747 preventDefault : function(){
6748 if(this.browserEvent){
6749 E.preventDefault(this.browserEvent);
6754 isNavKeyPress : function(){
6755 var k = this.keyCode;
6756 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6757 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6760 isSpecialKey : function(){
6761 var k = this.keyCode;
6762 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6763 (k == 16) || (k == 17) ||
6764 (k >= 18 && k <= 20) ||
6765 (k >= 33 && k <= 35) ||
6766 (k >= 36 && k <= 39) ||
6767 (k >= 44 && k <= 45);
6770 * Cancels bubbling of the event.
6772 stopPropagation : function(){
6773 if(this.browserEvent){
6774 if(this.type == 'mousedown'){
6775 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6777 E.stopPropagation(this.browserEvent);
6782 * Gets the key code for the event.
6785 getCharCode : function(){
6786 return this.charCode || this.keyCode;
6790 * Returns a normalized keyCode for the event.
6791 * @return {Number} The key code
6793 getKey : function(){
6794 var k = this.keyCode || this.charCode;
6795 return Roo.isSafari ? (safariKeys[k] || k) : k;
6799 * Gets the x coordinate of the event.
6802 getPageX : function(){
6807 * Gets the y coordinate of the event.
6810 getPageY : function(){
6815 * Gets the time of the event.
6818 getTime : function(){
6819 if(this.browserEvent){
6820 return E.getTime(this.browserEvent);
6826 * Gets the page coordinates of the event.
6827 * @return {Array} The xy values like [x, y]
6834 * Gets the target for the event.
6835 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6836 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6837 search as a number or element (defaults to 10 || document.body)
6838 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6839 * @return {HTMLelement}
6841 getTarget : function(selector, maxDepth, returnEl){
6842 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6845 * Gets the related target.
6846 * @return {HTMLElement}
6848 getRelatedTarget : function(){
6849 if(this.browserEvent){
6850 return E.getRelatedTarget(this.browserEvent);
6856 * Normalizes mouse wheel delta across browsers
6857 * @return {Number} The delta
6859 getWheelDelta : function(){
6860 var e = this.browserEvent;
6862 if(e.wheelDelta){ /* IE/Opera. */
6863 delta = e.wheelDelta/120;
6864 }else if(e.detail){ /* Mozilla case. */
6865 delta = -e.detail/3;
6871 * Returns true if the control, meta, shift or alt key was pressed during this event.
6874 hasModifier : function(){
6875 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6879 * Returns true if the target of this event equals el or is a child of el
6880 * @param {String/HTMLElement/Element} el
6881 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6884 within : function(el, related){
6885 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6886 return t && Roo.fly(el).contains(t);
6889 getPoint : function(){
6890 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6894 return new Roo.EventObjectImpl();
6899 * Ext JS Library 1.1.1
6900 * Copyright(c) 2006-2007, Ext JS, LLC.
6902 * Originally Released Under LGPL - original licence link has changed is not relivant.
6905 * <script type="text/javascript">
6909 // was in Composite Element!??!?!
6912 var D = Roo.lib.Dom;
6913 var E = Roo.lib.Event;
6914 var A = Roo.lib.Anim;
6916 // local style camelizing for speed
6918 var camelRe = /(-[a-z])/gi;
6919 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6920 var view = document.defaultView;
6923 * @class Roo.Element
6924 * Represents an Element in the DOM.<br><br>
6927 var el = Roo.get("my-div");
6930 var el = getEl("my-div");
6932 // or with a DOM element
6933 var el = Roo.get(myDivElement);
6935 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6936 * each call instead of constructing a new one.<br><br>
6937 * <b>Animations</b><br />
6938 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6939 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6941 Option Default Description
6942 --------- -------- ---------------------------------------------
6943 duration .35 The duration of the animation in seconds
6944 easing easeOut The YUI easing method
6945 callback none A function to execute when the anim completes
6946 scope this The scope (this) of the callback function
6948 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6949 * manipulate the animation. Here's an example:
6951 var el = Roo.get("my-div");
6956 // default animation
6957 el.setWidth(100, true);
6959 // animation with some options set
6966 // using the "anim" property to get the Anim object
6972 el.setWidth(100, opt);
6974 if(opt.anim.isAnimated()){
6978 * <b> Composite (Collections of) Elements</b><br />
6979 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6980 * @constructor Create a new Element directly.
6981 * @param {String/HTMLElement} element
6982 * @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).
6984 Roo.Element = function(element, forceNew){
6985 var dom = typeof element == "string" ?
6986 document.getElementById(element) : element;
6987 if(!dom){ // invalid id/element
6991 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6992 return Roo.Element.cache[id];
7002 * The DOM element ID
7005 this.id = id || Roo.id(dom);
7008 var El = Roo.Element;
7012 * The element's default display mode (defaults to "")
7015 originalDisplay : "",
7019 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7024 * Sets the element's visibility mode. When setVisible() is called it
7025 * will use this to determine whether to set the visibility or the display property.
7026 * @param visMode Element.VISIBILITY or Element.DISPLAY
7027 * @return {Roo.Element} this
7029 setVisibilityMode : function(visMode){
7030 this.visibilityMode = visMode;
7034 * Convenience method for setVisibilityMode(Element.DISPLAY)
7035 * @param {String} display (optional) What to set display to when visible
7036 * @return {Roo.Element} this
7038 enableDisplayMode : function(display){
7039 this.setVisibilityMode(El.DISPLAY);
7040 if(typeof display != "undefined") this.originalDisplay = display;
7045 * 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)
7046 * @param {String} selector The simple selector to test
7047 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7048 search as a number or element (defaults to 10 || document.body)
7049 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7050 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7052 findParent : function(simpleSelector, maxDepth, returnEl){
7053 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7054 maxDepth = maxDepth || 50;
7055 if(typeof maxDepth != "number"){
7056 stopEl = Roo.getDom(maxDepth);
7059 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7060 if(dq.is(p, simpleSelector)){
7061 return returnEl ? Roo.get(p) : p;
7071 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7072 * @param {String} selector The simple selector to test
7073 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7074 search as a number or element (defaults to 10 || document.body)
7075 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7076 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7078 findParentNode : function(simpleSelector, maxDepth, returnEl){
7079 var p = Roo.fly(this.dom.parentNode, '_internal');
7080 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7084 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7085 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7086 * @param {String} selector The simple selector to test
7087 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7088 search as a number or element (defaults to 10 || document.body)
7089 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7091 up : function(simpleSelector, maxDepth){
7092 return this.findParentNode(simpleSelector, maxDepth, true);
7098 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7099 * @param {String} selector The simple selector to test
7100 * @return {Boolean} True if this element matches the selector, else false
7102 is : function(simpleSelector){
7103 return Roo.DomQuery.is(this.dom, simpleSelector);
7107 * Perform animation on this element.
7108 * @param {Object} args The YUI animation control args
7109 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7110 * @param {Function} onComplete (optional) Function to call when animation completes
7111 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7112 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7113 * @return {Roo.Element} this
7115 animate : function(args, duration, onComplete, easing, animType){
7116 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7121 * @private Internal animation call
7123 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7124 animType = animType || 'run';
7126 var anim = Roo.lib.Anim[animType](
7128 (opt.duration || defaultDur) || .35,
7129 (opt.easing || defaultEase) || 'easeOut',
7131 Roo.callback(cb, this);
7132 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7140 // private legacy anim prep
7141 preanim : function(a, i){
7142 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7146 * Removes worthless text nodes
7147 * @param {Boolean} forceReclean (optional) By default the element
7148 * keeps track if it has been cleaned already so
7149 * you can call this over and over. However, if you update the element and
7150 * need to force a reclean, you can pass true.
7152 clean : function(forceReclean){
7153 if(this.isCleaned && forceReclean !== true){
7157 var d = this.dom, n = d.firstChild, ni = -1;
7159 var nx = n.nextSibling;
7160 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7167 this.isCleaned = true;
7172 calcOffsetsTo : function(el){
7175 var restorePos = false;
7176 if(el.getStyle('position') == 'static'){
7177 el.position('relative');
7182 while(op && op != d && op.tagName != 'HTML'){
7185 op = op.offsetParent;
7188 el.position('static');
7194 * Scrolls this element into view within the passed container.
7195 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7196 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7197 * @return {Roo.Element} this
7199 scrollIntoView : function(container, hscroll){
7200 var c = Roo.getDom(container) || document.body;
7203 var o = this.calcOffsetsTo(c),
7206 b = t+el.offsetHeight,
7207 r = l+el.offsetWidth;
7209 var ch = c.clientHeight;
7210 var ct = parseInt(c.scrollTop, 10);
7211 var cl = parseInt(c.scrollLeft, 10);
7213 var cr = cl + c.clientWidth;
7221 if(hscroll !== false){
7225 c.scrollLeft = r-c.clientWidth;
7232 scrollChildIntoView : function(child, hscroll){
7233 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7237 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7238 * the new height may not be available immediately.
7239 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7240 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7241 * @param {Function} onComplete (optional) Function to call when animation completes
7242 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7243 * @return {Roo.Element} this
7245 autoHeight : function(animate, duration, onComplete, easing){
7246 var oldHeight = this.getHeight();
7248 this.setHeight(1); // force clipping
7249 setTimeout(function(){
7250 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7252 this.setHeight(height);
7254 if(typeof onComplete == "function"){
7258 this.setHeight(oldHeight); // restore original height
7259 this.setHeight(height, animate, duration, function(){
7261 if(typeof onComplete == "function") onComplete();
7262 }.createDelegate(this), easing);
7264 }.createDelegate(this), 0);
7269 * Returns true if this element is an ancestor of the passed element
7270 * @param {HTMLElement/String} el The element to check
7271 * @return {Boolean} True if this element is an ancestor of el, else false
7273 contains : function(el){
7274 if(!el){return false;}
7275 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7279 * Checks whether the element is currently visible using both visibility and display properties.
7280 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7281 * @return {Boolean} True if the element is currently visible, else false
7283 isVisible : function(deep) {
7284 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7285 if(deep !== true || !vis){
7288 var p = this.dom.parentNode;
7289 while(p && p.tagName.toLowerCase() != "body"){
7290 if(!Roo.fly(p, '_isVisible').isVisible()){
7299 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7300 * @param {String} selector The CSS selector
7301 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7302 * @return {CompositeElement/CompositeElementLite} The composite element
7304 select : function(selector, unique){
7305 return El.select(selector, unique, this.dom);
7309 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7310 * @param {String} selector The CSS selector
7311 * @return {Array} An array of the matched nodes
7313 query : function(selector, unique){
7314 return Roo.DomQuery.select(selector, this.dom);
7318 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7319 * @param {String} selector The CSS selector
7320 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7321 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7323 child : function(selector, returnDom){
7324 var n = Roo.DomQuery.selectNode(selector, this.dom);
7325 return returnDom ? n : Roo.get(n);
7329 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7330 * @param {String} selector The CSS selector
7331 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7332 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7334 down : function(selector, returnDom){
7335 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7336 return returnDom ? n : Roo.get(n);
7340 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7341 * @param {String} group The group the DD object is member of
7342 * @param {Object} config The DD config object
7343 * @param {Object} overrides An object containing methods to override/implement on the DD object
7344 * @return {Roo.dd.DD} The DD object
7346 initDD : function(group, config, overrides){
7347 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7348 return Roo.apply(dd, overrides);
7352 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7353 * @param {String} group The group the DDProxy object is member of
7354 * @param {Object} config The DDProxy config object
7355 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7356 * @return {Roo.dd.DDProxy} The DDProxy object
7358 initDDProxy : function(group, config, overrides){
7359 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7360 return Roo.apply(dd, overrides);
7364 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7365 * @param {String} group The group the DDTarget object is member of
7366 * @param {Object} config The DDTarget config object
7367 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7368 * @return {Roo.dd.DDTarget} The DDTarget object
7370 initDDTarget : function(group, config, overrides){
7371 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7372 return Roo.apply(dd, overrides);
7376 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7377 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7378 * @param {Boolean} visible Whether the element is visible
7379 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7380 * @return {Roo.Element} this
7382 setVisible : function(visible, animate){
7384 if(this.visibilityMode == El.DISPLAY){
7385 this.setDisplayed(visible);
7388 this.dom.style.visibility = visible ? "visible" : "hidden";
7391 // closure for composites
7393 var visMode = this.visibilityMode;
7395 this.setOpacity(.01);
7396 this.setVisible(true);
7398 this.anim({opacity: { to: (visible?1:0) }},
7399 this.preanim(arguments, 1),
7400 null, .35, 'easeIn', function(){
7402 if(visMode == El.DISPLAY){
7403 dom.style.display = "none";
7405 dom.style.visibility = "hidden";
7407 Roo.get(dom).setOpacity(1);
7415 * Returns true if display is not "none"
7418 isDisplayed : function() {
7419 return this.getStyle("display") != "none";
7423 * Toggles the element's visibility or display, depending on visibility mode.
7424 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7425 * @return {Roo.Element} this
7427 toggle : function(animate){
7428 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7433 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7434 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7435 * @return {Roo.Element} this
7437 setDisplayed : function(value) {
7438 if(typeof value == "boolean"){
7439 value = value ? this.originalDisplay : "none";
7441 this.setStyle("display", value);
7446 * Tries to focus the element. Any exceptions are caught and ignored.
7447 * @return {Roo.Element} this
7449 focus : function() {
7457 * Tries to blur the element. Any exceptions are caught and ignored.
7458 * @return {Roo.Element} this
7468 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7469 * @param {String/Array} className The CSS class to add, or an array of classes
7470 * @return {Roo.Element} this
7472 addClass : function(className){
7473 if(className instanceof Array){
7474 for(var i = 0, len = className.length; i < len; i++) {
7475 this.addClass(className[i]);
7478 if(className && !this.hasClass(className)){
7479 this.dom.className = this.dom.className + " " + className;
7486 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7487 * @param {String/Array} className The CSS class to add, or an array of classes
7488 * @return {Roo.Element} this
7490 radioClass : function(className){
7491 var siblings = this.dom.parentNode.childNodes;
7492 for(var i = 0; i < siblings.length; i++) {
7493 var s = siblings[i];
7494 if(s.nodeType == 1){
7495 Roo.get(s).removeClass(className);
7498 this.addClass(className);
7503 * Removes one or more CSS classes from the element.
7504 * @param {String/Array} className The CSS class to remove, or an array of classes
7505 * @return {Roo.Element} this
7507 removeClass : function(className){
7508 if(!className || !this.dom.className){
7511 if(className instanceof Array){
7512 for(var i = 0, len = className.length; i < len; i++) {
7513 this.removeClass(className[i]);
7516 if(this.hasClass(className)){
7517 var re = this.classReCache[className];
7519 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7520 this.classReCache[className] = re;
7522 this.dom.className =
7523 this.dom.className.replace(re, " ");
7533 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7534 * @param {String} className The CSS class to toggle
7535 * @return {Roo.Element} this
7537 toggleClass : function(className){
7538 if(this.hasClass(className)){
7539 this.removeClass(className);
7541 this.addClass(className);
7547 * Checks if the specified CSS class exists on this element's DOM node.
7548 * @param {String} className The CSS class to check for
7549 * @return {Boolean} True if the class exists, else false
7551 hasClass : function(className){
7552 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7556 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7557 * @param {String} oldClassName The CSS class to replace
7558 * @param {String} newClassName The replacement CSS class
7559 * @return {Roo.Element} this
7561 replaceClass : function(oldClassName, newClassName){
7562 this.removeClass(oldClassName);
7563 this.addClass(newClassName);
7568 * Returns an object with properties matching the styles requested.
7569 * For example, el.getStyles('color', 'font-size', 'width') might return
7570 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7571 * @param {String} style1 A style name
7572 * @param {String} style2 A style name
7573 * @param {String} etc.
7574 * @return {Object} The style object
7576 getStyles : function(){
7577 var a = arguments, len = a.length, r = {};
7578 for(var i = 0; i < len; i++){
7579 r[a[i]] = this.getStyle(a[i]);
7585 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7586 * @param {String} property The style property whose value is returned.
7587 * @return {String} The current value of the style property for this element.
7589 getStyle : function(){
7590 return view && view.getComputedStyle ?
7592 var el = this.dom, v, cs, camel;
7593 if(prop == 'float'){
7596 if(el.style && (v = el.style[prop])){
7599 if(cs = view.getComputedStyle(el, "")){
7600 if(!(camel = propCache[prop])){
7601 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7608 var el = this.dom, v, cs, camel;
7609 if(prop == 'opacity'){
7610 if(typeof el.style.filter == 'string'){
7611 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7613 var fv = parseFloat(m[1]);
7615 return fv ? fv / 100 : 0;
7620 }else if(prop == 'float'){
7621 prop = "styleFloat";
7623 if(!(camel = propCache[prop])){
7624 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7626 if(v = el.style[camel]){
7629 if(cs = el.currentStyle){
7637 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7638 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7639 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7640 * @return {Roo.Element} this
7642 setStyle : function(prop, value){
7643 if(typeof prop == "string"){
7645 if (prop == 'float') {
7646 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7651 if(!(camel = propCache[prop])){
7652 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7655 if(camel == 'opacity') {
7656 this.setOpacity(value);
7658 this.dom.style[camel] = value;
7661 for(var style in prop){
7662 if(typeof prop[style] != "function"){
7663 this.setStyle(style, prop[style]);
7671 * More flexible version of {@link #setStyle} for setting style properties.
7672 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7673 * a function which returns such a specification.
7674 * @return {Roo.Element} this
7676 applyStyles : function(style){
7677 Roo.DomHelper.applyStyles(this.dom, style);
7682 * 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).
7683 * @return {Number} The X position of the element
7686 return D.getX(this.dom);
7690 * 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).
7691 * @return {Number} The Y position of the element
7694 return D.getY(this.dom);
7698 * 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).
7699 * @return {Array} The XY position of the element
7702 return D.getXY(this.dom);
7706 * 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).
7707 * @param {Number} The X position of the element
7708 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7709 * @return {Roo.Element} this
7711 setX : function(x, animate){
7713 D.setX(this.dom, x);
7715 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7721 * 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).
7722 * @param {Number} The Y position of the element
7723 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7724 * @return {Roo.Element} this
7726 setY : function(y, animate){
7728 D.setY(this.dom, y);
7730 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7736 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7737 * @param {String} left The left CSS property value
7738 * @return {Roo.Element} this
7740 setLeft : function(left){
7741 this.setStyle("left", this.addUnits(left));
7746 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7747 * @param {String} top The top CSS property value
7748 * @return {Roo.Element} this
7750 setTop : function(top){
7751 this.setStyle("top", this.addUnits(top));
7756 * Sets the element's CSS right style.
7757 * @param {String} right The right CSS property value
7758 * @return {Roo.Element} this
7760 setRight : function(right){
7761 this.setStyle("right", this.addUnits(right));
7766 * Sets the element's CSS bottom style.
7767 * @param {String} bottom The bottom CSS property value
7768 * @return {Roo.Element} this
7770 setBottom : function(bottom){
7771 this.setStyle("bottom", this.addUnits(bottom));
7776 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7777 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7778 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7779 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7780 * @return {Roo.Element} this
7782 setXY : function(pos, animate){
7784 D.setXY(this.dom, pos);
7786 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7792 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7793 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7794 * @param {Number} x X value for new position (coordinates are page-based)
7795 * @param {Number} y Y value for new position (coordinates are page-based)
7796 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7797 * @return {Roo.Element} this
7799 setLocation : function(x, y, animate){
7800 this.setXY([x, y], this.preanim(arguments, 2));
7805 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7806 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7807 * @param {Number} x X value for new position (coordinates are page-based)
7808 * @param {Number} y Y value for new position (coordinates are page-based)
7809 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7810 * @return {Roo.Element} this
7812 moveTo : function(x, y, animate){
7813 this.setXY([x, y], this.preanim(arguments, 2));
7818 * Returns the region of the given element.
7819 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7820 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7822 getRegion : function(){
7823 return D.getRegion(this.dom);
7827 * Returns the offset height of the element
7828 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7829 * @return {Number} The element's height
7831 getHeight : function(contentHeight){
7832 var h = this.dom.offsetHeight || 0;
7833 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7837 * Returns the offset width of the element
7838 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7839 * @return {Number} The element's width
7841 getWidth : function(contentWidth){
7842 var w = this.dom.offsetWidth || 0;
7843 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7847 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7848 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7849 * if a height has not been set using CSS.
7852 getComputedHeight : function(){
7853 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7855 h = parseInt(this.getStyle('height'), 10) || 0;
7856 if(!this.isBorderBox()){
7857 h += this.getFrameWidth('tb');
7864 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7865 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7866 * if a width has not been set using CSS.
7869 getComputedWidth : function(){
7870 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7872 w = parseInt(this.getStyle('width'), 10) || 0;
7873 if(!this.isBorderBox()){
7874 w += this.getFrameWidth('lr');
7881 * Returns the size of the element.
7882 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7883 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7885 getSize : function(contentSize){
7886 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7890 * Returns the width and height of the viewport.
7891 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7893 getViewSize : function(){
7894 var d = this.dom, doc = document, aw = 0, ah = 0;
7895 if(d == doc || d == doc.body){
7896 return {width : D.getViewWidth(), height: D.getViewHeight()};
7899 width : d.clientWidth,
7900 height: d.clientHeight
7906 * Returns the value of the "value" attribute
7907 * @param {Boolean} asNumber true to parse the value as a number
7908 * @return {String/Number}
7910 getValue : function(asNumber){
7911 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7915 adjustWidth : function(width){
7916 if(typeof width == "number"){
7917 if(this.autoBoxAdjust && !this.isBorderBox()){
7918 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7928 adjustHeight : function(height){
7929 if(typeof height == "number"){
7930 if(this.autoBoxAdjust && !this.isBorderBox()){
7931 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7941 * Set the width of the element
7942 * @param {Number} width The new width
7943 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7944 * @return {Roo.Element} this
7946 setWidth : function(width, animate){
7947 width = this.adjustWidth(width);
7949 this.dom.style.width = this.addUnits(width);
7951 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7957 * Set the height of the element
7958 * @param {Number} height The new height
7959 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7960 * @return {Roo.Element} this
7962 setHeight : function(height, animate){
7963 height = this.adjustHeight(height);
7965 this.dom.style.height = this.addUnits(height);
7967 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7973 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7974 * @param {Number} width The new width
7975 * @param {Number} height The new height
7976 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7977 * @return {Roo.Element} this
7979 setSize : function(width, height, animate){
7980 if(typeof width == "object"){ // in case of object from getSize()
7981 height = width.height; width = width.width;
7983 width = this.adjustWidth(width); height = this.adjustHeight(height);
7985 this.dom.style.width = this.addUnits(width);
7986 this.dom.style.height = this.addUnits(height);
7988 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7994 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7995 * @param {Number} x X value for new position (coordinates are page-based)
7996 * @param {Number} y Y value for new position (coordinates are page-based)
7997 * @param {Number} width The new width
7998 * @param {Number} height The new height
7999 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8000 * @return {Roo.Element} this
8002 setBounds : function(x, y, width, height, animate){
8004 this.setSize(width, height);
8005 this.setLocation(x, y);
8007 width = this.adjustWidth(width); height = this.adjustHeight(height);
8008 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8009 this.preanim(arguments, 4), 'motion');
8015 * 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.
8016 * @param {Roo.lib.Region} region The region to fill
8017 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8018 * @return {Roo.Element} this
8020 setRegion : function(region, animate){
8021 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8026 * Appends an event handler
8028 * @param {String} eventName The type of event to append
8029 * @param {Function} fn The method the event invokes
8030 * @param {Object} scope (optional) The scope (this object) of the fn
8031 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8033 addListener : function(eventName, fn, scope, options){
8035 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8040 * Removes an event handler from this element
8041 * @param {String} eventName the type of event to remove
8042 * @param {Function} fn the method the event invokes
8043 * @return {Roo.Element} this
8045 removeListener : function(eventName, fn){
8046 Roo.EventManager.removeListener(this.dom, eventName, fn);
8051 * Removes all previous added listeners from this element
8052 * @return {Roo.Element} this
8054 removeAllListeners : function(){
8055 E.purgeElement(this.dom);
8059 relayEvent : function(eventName, observable){
8060 this.on(eventName, function(e){
8061 observable.fireEvent(eventName, e);
8066 * Set the opacity of the element
8067 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8068 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8069 * @return {Roo.Element} this
8071 setOpacity : function(opacity, animate){
8073 var s = this.dom.style;
8076 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8077 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8079 s.opacity = opacity;
8082 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8088 * Gets the left X coordinate
8089 * @param {Boolean} local True to get the local css position instead of page coordinate
8092 getLeft : function(local){
8096 return parseInt(this.getStyle("left"), 10) || 0;
8101 * Gets the right X coordinate of the element (element X position + element width)
8102 * @param {Boolean} local True to get the local css position instead of page coordinate
8105 getRight : function(local){
8107 return this.getX() + this.getWidth();
8109 return (this.getLeft(true) + this.getWidth()) || 0;
8114 * Gets the top Y coordinate
8115 * @param {Boolean} local True to get the local css position instead of page coordinate
8118 getTop : function(local) {
8122 return parseInt(this.getStyle("top"), 10) || 0;
8127 * Gets the bottom Y coordinate of the element (element Y position + element height)
8128 * @param {Boolean} local True to get the local css position instead of page coordinate
8131 getBottom : function(local){
8133 return this.getY() + this.getHeight();
8135 return (this.getTop(true) + this.getHeight()) || 0;
8140 * Initializes positioning on this element. If a desired position is not passed, it will make the
8141 * the element positioned relative IF it is not already positioned.
8142 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8143 * @param {Number} zIndex (optional) The zIndex to apply
8144 * @param {Number} x (optional) Set the page X position
8145 * @param {Number} y (optional) Set the page Y position
8147 position : function(pos, zIndex, x, y){
8149 if(this.getStyle('position') == 'static'){
8150 this.setStyle('position', 'relative');
8153 this.setStyle("position", pos);
8156 this.setStyle("z-index", zIndex);
8158 if(x !== undefined && y !== undefined){
8160 }else if(x !== undefined){
8162 }else if(y !== undefined){
8168 * Clear positioning back to the default when the document was loaded
8169 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8170 * @return {Roo.Element} this
8172 clearPositioning : function(value){
8180 "position" : "static"
8186 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8187 * snapshot before performing an update and then restoring the element.
8190 getPositioning : function(){
8191 var l = this.getStyle("left");
8192 var t = this.getStyle("top");
8194 "position" : this.getStyle("position"),
8196 "right" : l ? "" : this.getStyle("right"),
8198 "bottom" : t ? "" : this.getStyle("bottom"),
8199 "z-index" : this.getStyle("z-index")
8204 * Gets the width of the border(s) for the specified side(s)
8205 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8206 * passing lr would get the border (l)eft width + the border (r)ight width.
8207 * @return {Number} The width of the sides passed added together
8209 getBorderWidth : function(side){
8210 return this.addStyles(side, El.borders);
8214 * Gets the width of the padding(s) for the specified side(s)
8215 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8216 * passing lr would get the padding (l)eft + the padding (r)ight.
8217 * @return {Number} The padding of the sides passed added together
8219 getPadding : function(side){
8220 return this.addStyles(side, El.paddings);
8224 * Set positioning with an object returned by getPositioning().
8225 * @param {Object} posCfg
8226 * @return {Roo.Element} this
8228 setPositioning : function(pc){
8229 this.applyStyles(pc);
8230 if(pc.right == "auto"){
8231 this.dom.style.right = "";
8233 if(pc.bottom == "auto"){
8234 this.dom.style.bottom = "";
8240 fixDisplay : function(){
8241 if(this.getStyle("display") == "none"){
8242 this.setStyle("visibility", "hidden");
8243 this.setStyle("display", this.originalDisplay); // first try reverting to default
8244 if(this.getStyle("display") == "none"){ // if that fails, default to block
8245 this.setStyle("display", "block");
8251 * Quick set left and top adding default units
8252 * @param {String} left The left CSS property value
8253 * @param {String} top The top CSS property value
8254 * @return {Roo.Element} this
8256 setLeftTop : function(left, top){
8257 this.dom.style.left = this.addUnits(left);
8258 this.dom.style.top = this.addUnits(top);
8263 * Move this element relative to its current position.
8264 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8265 * @param {Number} distance How far to move the element in pixels
8266 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8267 * @return {Roo.Element} this
8269 move : function(direction, distance, animate){
8270 var xy = this.getXY();
8271 direction = direction.toLowerCase();
8275 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8279 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8284 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8289 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8296 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8297 * @return {Roo.Element} this
8300 if(!this.isClipped){
8301 this.isClipped = true;
8302 this.originalClip = {
8303 "o": this.getStyle("overflow"),
8304 "x": this.getStyle("overflow-x"),
8305 "y": this.getStyle("overflow-y")
8307 this.setStyle("overflow", "hidden");
8308 this.setStyle("overflow-x", "hidden");
8309 this.setStyle("overflow-y", "hidden");
8315 * Return clipping (overflow) to original clipping before clip() was called
8316 * @return {Roo.Element} this
8318 unclip : function(){
8320 this.isClipped = false;
8321 var o = this.originalClip;
8322 if(o.o){this.setStyle("overflow", o.o);}
8323 if(o.x){this.setStyle("overflow-x", o.x);}
8324 if(o.y){this.setStyle("overflow-y", o.y);}
8331 * Gets the x,y coordinates specified by the anchor position on the element.
8332 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8333 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8334 * {width: (target width), height: (target height)} (defaults to the element's current size)
8335 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8336 * @return {Array} [x, y] An array containing the element's x and y coordinates
8338 getAnchorXY : function(anchor, local, s){
8339 //Passing a different size is useful for pre-calculating anchors,
8340 //especially for anchored animations that change the el size.
8342 var w, h, vp = false;
8345 if(d == document.body || d == document){
8347 w = D.getViewWidth(); h = D.getViewHeight();
8349 w = this.getWidth(); h = this.getHeight();
8352 w = s.width; h = s.height;
8354 var x = 0, y = 0, r = Math.round;
8355 switch((anchor || "tl").toLowerCase()){
8397 var sc = this.getScroll();
8398 return [x + sc.left, y + sc.top];
8400 //Add the element's offset xy
8401 var o = this.getXY();
8402 return [x+o[0], y+o[1]];
8406 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8407 * supported position values.
8408 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8409 * @param {String} position The position to align to.
8410 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8411 * @return {Array} [x, y]
8413 getAlignToXY : function(el, p, o){
8417 throw "Element.alignTo with an element that doesn't exist";
8419 var c = false; //constrain to viewport
8420 var p1 = "", p2 = "";
8427 }else if(p.indexOf("-") == -1){
8430 p = p.toLowerCase();
8431 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8433 throw "Element.alignTo with an invalid alignment " + p;
8435 p1 = m[1]; p2 = m[2]; c = !!m[3];
8437 //Subtract the aligned el's internal xy from the target's offset xy
8438 //plus custom offset to get the aligned el's new offset xy
8439 var a1 = this.getAnchorXY(p1, true);
8440 var a2 = el.getAnchorXY(p2, false);
8441 var x = a2[0] - a1[0] + o[0];
8442 var y = a2[1] - a1[1] + o[1];
8444 //constrain the aligned el to viewport if necessary
8445 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8446 // 5px of margin for ie
8447 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8449 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8450 //perpendicular to the vp border, allow the aligned el to slide on that border,
8451 //otherwise swap the aligned el to the opposite border of the target.
8452 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8453 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8454 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8455 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8458 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8459 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8461 if((x+w) > dw + scrollX){
8462 x = swapX ? r.left-w : dw+scrollX-w;
8465 x = swapX ? r.right : scrollX;
8467 if((y+h) > dh + scrollY){
8468 y = swapY ? r.top-h : dh+scrollY-h;
8471 y = swapY ? r.bottom : scrollY;
8478 getConstrainToXY : function(){
8479 var os = {top:0, left:0, bottom:0, right: 0};
8481 return function(el, local, offsets, proposedXY){
8483 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8485 var vw, vh, vx = 0, vy = 0;
8486 if(el.dom == document.body || el.dom == document){
8487 vw = Roo.lib.Dom.getViewWidth();
8488 vh = Roo.lib.Dom.getViewHeight();
8490 vw = el.dom.clientWidth;
8491 vh = el.dom.clientHeight;
8493 var vxy = el.getXY();
8499 var s = el.getScroll();
8501 vx += offsets.left + s.left;
8502 vy += offsets.top + s.top;
8504 vw -= offsets.right;
8505 vh -= offsets.bottom;
8510 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8511 var x = xy[0], y = xy[1];
8512 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8514 // only move it if it needs it
8517 // first validate right/bottom
8526 // then make sure top/left isn't negative
8535 return moved ? [x, y] : false;
8540 adjustForConstraints : function(xy, parent, offsets){
8541 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8545 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8546 * document it aligns it to the viewport.
8547 * The position parameter is optional, and can be specified in any one of the following formats:
8549 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8550 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8551 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8552 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8553 * <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
8554 * element's anchor point, and the second value is used as the target's anchor point.</li>
8556 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8557 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8558 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8559 * that specified in order to enforce the viewport constraints.
8560 * Following are all of the supported anchor positions:
8563 ----- -----------------------------
8564 tl The top left corner (default)
8565 t The center of the top edge
8566 tr The top right corner
8567 l The center of the left edge
8568 c In the center of the element
8569 r The center of the right edge
8570 bl The bottom left corner
8571 b The center of the bottom edge
8572 br The bottom right corner
8576 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8577 el.alignTo("other-el");
8579 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8580 el.alignTo("other-el", "tr?");
8582 // align the bottom right corner of el with the center left edge of other-el
8583 el.alignTo("other-el", "br-l?");
8585 // align the center of el with the bottom left corner of other-el and
8586 // adjust the x position by -6 pixels (and the y position by 0)
8587 el.alignTo("other-el", "c-bl", [-6, 0]);
8589 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8590 * @param {String} position The position to align to.
8591 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8592 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8593 * @return {Roo.Element} this
8595 alignTo : function(element, position, offsets, animate){
8596 var xy = this.getAlignToXY(element, position, offsets);
8597 this.setXY(xy, this.preanim(arguments, 3));
8602 * Anchors an element to another element and realigns it when the window is resized.
8603 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8604 * @param {String} position The position to align to.
8605 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8606 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8607 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8608 * is a number, it is used as the buffer delay (defaults to 50ms).
8609 * @param {Function} callback The function to call after the animation finishes
8610 * @return {Roo.Element} this
8612 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8613 var action = function(){
8614 this.alignTo(el, alignment, offsets, animate);
8615 Roo.callback(callback, this);
8617 Roo.EventManager.onWindowResize(action, this);
8618 var tm = typeof monitorScroll;
8619 if(tm != 'undefined'){
8620 Roo.EventManager.on(window, 'scroll', action, this,
8621 {buffer: tm == 'number' ? monitorScroll : 50});
8623 action.call(this); // align immediately
8627 * Clears any opacity settings from this element. Required in some cases for IE.
8628 * @return {Roo.Element} this
8630 clearOpacity : function(){
8631 if (window.ActiveXObject) {
8632 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8633 this.dom.style.filter = "";
8636 this.dom.style.opacity = "";
8637 this.dom.style["-moz-opacity"] = "";
8638 this.dom.style["-khtml-opacity"] = "";
8644 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8645 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8646 * @return {Roo.Element} this
8648 hide : function(animate){
8649 this.setVisible(false, this.preanim(arguments, 0));
8654 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8655 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8656 * @return {Roo.Element} this
8658 show : function(animate){
8659 this.setVisible(true, this.preanim(arguments, 0));
8664 * @private Test if size has a unit, otherwise appends the default
8666 addUnits : function(size){
8667 return Roo.Element.addUnits(size, this.defaultUnit);
8671 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8672 * @return {Roo.Element} this
8674 beginMeasure : function(){
8676 if(el.offsetWidth || el.offsetHeight){
8677 return this; // offsets work already
8680 var p = this.dom, b = document.body; // start with this element
8681 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8682 var pe = Roo.get(p);
8683 if(pe.getStyle('display') == 'none'){
8684 changed.push({el: p, visibility: pe.getStyle("visibility")});
8685 p.style.visibility = "hidden";
8686 p.style.display = "block";
8690 this._measureChanged = changed;
8696 * Restores displays to before beginMeasure was called
8697 * @return {Roo.Element} this
8699 endMeasure : function(){
8700 var changed = this._measureChanged;
8702 for(var i = 0, len = changed.length; i < len; i++) {
8704 r.el.style.visibility = r.visibility;
8705 r.el.style.display = "none";
8707 this._measureChanged = null;
8713 * Update the innerHTML of this element, optionally searching for and processing scripts
8714 * @param {String} html The new HTML
8715 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8716 * @param {Function} callback For async script loading you can be noticed when the update completes
8717 * @return {Roo.Element} this
8719 update : function(html, loadScripts, callback){
8720 if(typeof html == "undefined"){
8723 if(loadScripts !== true){
8724 this.dom.innerHTML = html;
8725 if(typeof callback == "function"){
8733 html += '<span id="' + id + '"></span>';
8735 E.onAvailable(id, function(){
8736 var hd = document.getElementsByTagName("head")[0];
8737 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8738 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8739 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8742 while(match = re.exec(html)){
8743 var attrs = match[1];
8744 var srcMatch = attrs ? attrs.match(srcRe) : false;
8745 if(srcMatch && srcMatch[2]){
8746 var s = document.createElement("script");
8747 s.src = srcMatch[2];
8748 var typeMatch = attrs.match(typeRe);
8749 if(typeMatch && typeMatch[2]){
8750 s.type = typeMatch[2];
8753 }else if(match[2] && match[2].length > 0){
8754 if(window.execScript) {
8755 window.execScript(match[2]);
8763 window.eval(match[2]);
8767 var el = document.getElementById(id);
8768 if(el){el.parentNode.removeChild(el);}
8769 if(typeof callback == "function"){
8773 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8778 * Direct access to the UpdateManager update() method (takes the same parameters).
8779 * @param {String/Function} url The url for this request or a function to call to get the url
8780 * @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}
8781 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8782 * @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.
8783 * @return {Roo.Element} this
8786 var um = this.getUpdateManager();
8787 um.update.apply(um, arguments);
8792 * Gets this element's UpdateManager
8793 * @return {Roo.UpdateManager} The UpdateManager
8795 getUpdateManager : function(){
8796 if(!this.updateManager){
8797 this.updateManager = new Roo.UpdateManager(this);
8799 return this.updateManager;
8803 * Disables text selection for this element (normalized across browsers)
8804 * @return {Roo.Element} this
8806 unselectable : function(){
8807 this.dom.unselectable = "on";
8808 this.swallowEvent("selectstart", true);
8809 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8810 this.addClass("x-unselectable");
8815 * Calculates the x, y to center this element on the screen
8816 * @return {Array} The x, y values [x, y]
8818 getCenterXY : function(){
8819 return this.getAlignToXY(document, 'c-c');
8823 * Centers the Element in either the viewport, or another Element.
8824 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8826 center : function(centerIn){
8827 this.alignTo(centerIn || document, 'c-c');
8832 * Tests various css rules/browsers to determine if this element uses a border box
8835 isBorderBox : function(){
8836 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8840 * Return a box {x, y, width, height} that can be used to set another elements
8841 * size/location to match this element.
8842 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8843 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8844 * @return {Object} box An object in the format {x, y, width, height}
8846 getBox : function(contentBox, local){
8851 var left = parseInt(this.getStyle("left"), 10) || 0;
8852 var top = parseInt(this.getStyle("top"), 10) || 0;
8855 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8857 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8859 var l = this.getBorderWidth("l")+this.getPadding("l");
8860 var r = this.getBorderWidth("r")+this.getPadding("r");
8861 var t = this.getBorderWidth("t")+this.getPadding("t");
8862 var b = this.getBorderWidth("b")+this.getPadding("b");
8863 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)};
8865 bx.right = bx.x + bx.width;
8866 bx.bottom = bx.y + bx.height;
8871 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8872 for more information about the sides.
8873 * @param {String} sides
8876 getFrameWidth : function(sides, onlyContentBox){
8877 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8881 * 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.
8882 * @param {Object} box The box to fill {x, y, width, height}
8883 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8884 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8885 * @return {Roo.Element} this
8887 setBox : function(box, adjust, animate){
8888 var w = box.width, h = box.height;
8889 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8890 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8891 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8893 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8898 * Forces the browser to repaint this element
8899 * @return {Roo.Element} this
8901 repaint : function(){
8903 this.addClass("x-repaint");
8904 setTimeout(function(){
8905 Roo.get(dom).removeClass("x-repaint");
8911 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8912 * then it returns the calculated width of the sides (see getPadding)
8913 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8914 * @return {Object/Number}
8916 getMargins : function(side){
8919 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8920 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8921 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8922 right: parseInt(this.getStyle("margin-right"), 10) || 0
8925 return this.addStyles(side, El.margins);
8930 addStyles : function(sides, styles){
8932 for(var i = 0, len = sides.length; i < len; i++){
8933 v = this.getStyle(styles[sides.charAt(i)]);
8935 w = parseInt(v, 10);
8943 * Creates a proxy element of this element
8944 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8945 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8946 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8947 * @return {Roo.Element} The new proxy element
8949 createProxy : function(config, renderTo, matchBox){
8951 renderTo = Roo.getDom(renderTo);
8953 renderTo = document.body;
8955 config = typeof config == "object" ?
8956 config : {tag : "div", cls: config};
8957 var proxy = Roo.DomHelper.append(renderTo, config, true);
8959 proxy.setBox(this.getBox());
8965 * Puts a mask over this element to disable user interaction. Requires core.css.
8966 * This method can only be applied to elements which accept child nodes.
8967 * @param {String} msg (optional) A message to display in the mask
8968 * @param {String} msgCls (optional) A css class to apply to the msg element
8969 * @return {Element} The mask element
8971 mask : function(msg, msgCls)
8973 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8974 this.setStyle("position", "relative");
8977 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8979 this.addClass("x-masked");
8980 this._mask.setDisplayed(true);
8985 while (dom && dom.style) {
8986 if (!isNaN(parseInt(dom.style.zIndex))) {
8987 z = Math.max(z, parseInt(dom.style.zIndex));
8989 dom = dom.parentNode;
8991 // if we are masking the body - then it hides everything..
8992 if (this.dom == document.body) {
8994 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8995 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8998 if(typeof msg == 'string'){
9000 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9002 var mm = this._maskMsg;
9003 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9004 mm.dom.firstChild.innerHTML = msg;
9005 mm.setDisplayed(true);
9007 mm.setStyle('z-index', z + 102);
9009 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9010 this._mask.setHeight(this.getHeight());
9012 this._mask.setStyle('z-index', z + 100);
9018 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9019 * it is cached for reuse.
9021 unmask : function(removeEl){
9023 if(removeEl === true){
9024 this._mask.remove();
9027 this._maskMsg.remove();
9028 delete this._maskMsg;
9031 this._mask.setDisplayed(false);
9033 this._maskMsg.setDisplayed(false);
9037 this.removeClass("x-masked");
9041 * Returns true if this element is masked
9044 isMasked : function(){
9045 return this._mask && this._mask.isVisible();
9049 * Creates an iframe shim for this element to keep selects and other windowed objects from
9051 * @return {Roo.Element} The new shim element
9053 createShim : function(){
9054 var el = document.createElement('iframe');
9055 el.frameBorder = 'no';
9056 el.className = 'roo-shim';
9057 if(Roo.isIE && Roo.isSecure){
9058 el.src = Roo.SSL_SECURE_URL;
9060 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9061 shim.autoBoxAdjust = false;
9066 * Removes this element from the DOM and deletes it from the cache
9068 remove : function(){
9069 if(this.dom.parentNode){
9070 this.dom.parentNode.removeChild(this.dom);
9072 delete El.cache[this.dom.id];
9076 * Sets up event handlers to add and remove a css class when the mouse is over this element
9077 * @param {String} className
9078 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9079 * mouseout events for children elements
9080 * @return {Roo.Element} this
9082 addClassOnOver : function(className, preventFlicker){
9083 this.on("mouseover", function(){
9084 Roo.fly(this, '_internal').addClass(className);
9086 var removeFn = function(e){
9087 if(preventFlicker !== true || !e.within(this, true)){
9088 Roo.fly(this, '_internal').removeClass(className);
9091 this.on("mouseout", removeFn, this.dom);
9096 * Sets up event handlers to add and remove a css class when this element has the focus
9097 * @param {String} className
9098 * @return {Roo.Element} this
9100 addClassOnFocus : function(className){
9101 this.on("focus", function(){
9102 Roo.fly(this, '_internal').addClass(className);
9104 this.on("blur", function(){
9105 Roo.fly(this, '_internal').removeClass(className);
9110 * 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)
9111 * @param {String} className
9112 * @return {Roo.Element} this
9114 addClassOnClick : function(className){
9116 this.on("mousedown", function(){
9117 Roo.fly(dom, '_internal').addClass(className);
9118 var d = Roo.get(document);
9119 var fn = function(){
9120 Roo.fly(dom, '_internal').removeClass(className);
9121 d.removeListener("mouseup", fn);
9123 d.on("mouseup", fn);
9129 * Stops the specified event from bubbling and optionally prevents the default action
9130 * @param {String} eventName
9131 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9132 * @return {Roo.Element} this
9134 swallowEvent : function(eventName, preventDefault){
9135 var fn = function(e){
9136 e.stopPropagation();
9141 if(eventName instanceof Array){
9142 for(var i = 0, len = eventName.length; i < len; i++){
9143 this.on(eventName[i], fn);
9147 this.on(eventName, fn);
9154 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9157 * Sizes this element to its parent element's dimensions performing
9158 * neccessary box adjustments.
9159 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9160 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9161 * @return {Roo.Element} this
9163 fitToParent : function(monitorResize, targetParent) {
9164 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9165 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9166 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9169 var p = Roo.get(targetParent || this.dom.parentNode);
9170 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9171 if (monitorResize === true) {
9172 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9173 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9179 * Gets the next sibling, skipping text nodes
9180 * @return {HTMLElement} The next sibling or null
9182 getNextSibling : function(){
9183 var n = this.dom.nextSibling;
9184 while(n && n.nodeType != 1){
9191 * Gets the previous sibling, skipping text nodes
9192 * @return {HTMLElement} The previous sibling or null
9194 getPrevSibling : function(){
9195 var n = this.dom.previousSibling;
9196 while(n && n.nodeType != 1){
9197 n = n.previousSibling;
9204 * Appends the passed element(s) to this element
9205 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9206 * @return {Roo.Element} this
9208 appendChild: function(el){
9215 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9216 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9217 * automatically generated with the specified attributes.
9218 * @param {HTMLElement} insertBefore (optional) a child element of this element
9219 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9220 * @return {Roo.Element} The new child element
9222 createChild: function(config, insertBefore, returnDom){
9223 config = config || {tag:'div'};
9225 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9227 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9231 * Appends this element to the passed element
9232 * @param {String/HTMLElement/Element} el The new parent element
9233 * @return {Roo.Element} this
9235 appendTo: function(el){
9236 el = Roo.getDom(el);
9237 el.appendChild(this.dom);
9242 * Inserts this element before the passed element in the DOM
9243 * @param {String/HTMLElement/Element} el The element to insert before
9244 * @return {Roo.Element} this
9246 insertBefore: function(el){
9247 el = Roo.getDom(el);
9248 el.parentNode.insertBefore(this.dom, el);
9253 * Inserts this element after the passed element in the DOM
9254 * @param {String/HTMLElement/Element} el The element to insert after
9255 * @return {Roo.Element} this
9257 insertAfter: function(el){
9258 el = Roo.getDom(el);
9259 el.parentNode.insertBefore(this.dom, el.nextSibling);
9264 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9265 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9266 * @return {Roo.Element} The new child
9268 insertFirst: function(el, returnDom){
9270 if(typeof el == 'object' && !el.nodeType){ // dh config
9271 return this.createChild(el, this.dom.firstChild, returnDom);
9273 el = Roo.getDom(el);
9274 this.dom.insertBefore(el, this.dom.firstChild);
9275 return !returnDom ? Roo.get(el) : el;
9280 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9281 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9282 * @param {String} where (optional) 'before' or 'after' defaults to before
9283 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9284 * @return {Roo.Element} the inserted Element
9286 insertSibling: function(el, where, returnDom){
9287 where = where ? where.toLowerCase() : 'before';
9289 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9291 if(typeof el == 'object' && !el.nodeType){ // dh config
9292 if(where == 'after' && !this.dom.nextSibling){
9293 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9295 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9299 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9300 where == 'before' ? this.dom : this.dom.nextSibling);
9309 * Creates and wraps this element with another element
9310 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9311 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9312 * @return {HTMLElement/Element} The newly created wrapper element
9314 wrap: function(config, returnDom){
9316 config = {tag: "div"};
9318 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9319 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9324 * Replaces the passed element with this element
9325 * @param {String/HTMLElement/Element} el The element to replace
9326 * @return {Roo.Element} this
9328 replace: function(el){
9330 this.insertBefore(el);
9336 * Inserts an html fragment into this element
9337 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9338 * @param {String} html The HTML fragment
9339 * @param {Boolean} returnEl True to return an Roo.Element
9340 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9342 insertHtml : function(where, html, returnEl){
9343 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9344 return returnEl ? Roo.get(el) : el;
9348 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9349 * @param {Object} o The object with the attributes
9350 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9351 * @return {Roo.Element} this
9353 set : function(o, useSet){
9355 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9357 if(attr == "style" || typeof o[attr] == "function") continue;
9359 el.className = o["cls"];
9361 if(useSet) el.setAttribute(attr, o[attr]);
9362 else el[attr] = o[attr];
9366 Roo.DomHelper.applyStyles(el, o.style);
9372 * Convenience method for constructing a KeyMap
9373 * @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:
9374 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9375 * @param {Function} fn The function to call
9376 * @param {Object} scope (optional) The scope of the function
9377 * @return {Roo.KeyMap} The KeyMap created
9379 addKeyListener : function(key, fn, scope){
9381 if(typeof key != "object" || key instanceof Array){
9397 return new Roo.KeyMap(this, config);
9401 * Creates a KeyMap for this element
9402 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9403 * @return {Roo.KeyMap} The KeyMap created
9405 addKeyMap : function(config){
9406 return new Roo.KeyMap(this, config);
9410 * Returns true if this element is scrollable.
9413 isScrollable : function(){
9415 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9419 * 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().
9420 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9421 * @param {Number} value The new scroll value
9422 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9423 * @return {Element} this
9426 scrollTo : function(side, value, animate){
9427 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9429 this.dom[prop] = value;
9431 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9432 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9438 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9439 * within this element's scrollable range.
9440 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9441 * @param {Number} distance How far to scroll the element in pixels
9442 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9443 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9444 * was scrolled as far as it could go.
9446 scroll : function(direction, distance, animate){
9447 if(!this.isScrollable()){
9451 var l = el.scrollLeft, t = el.scrollTop;
9452 var w = el.scrollWidth, h = el.scrollHeight;
9453 var cw = el.clientWidth, ch = el.clientHeight;
9454 direction = direction.toLowerCase();
9455 var scrolled = false;
9456 var a = this.preanim(arguments, 2);
9461 var v = Math.min(l + distance, w-cw);
9462 this.scrollTo("left", v, a);
9469 var v = Math.max(l - distance, 0);
9470 this.scrollTo("left", v, a);
9478 var v = Math.max(t - distance, 0);
9479 this.scrollTo("top", v, a);
9487 var v = Math.min(t + distance, h-ch);
9488 this.scrollTo("top", v, a);
9497 * Translates the passed page coordinates into left/top css values for this element
9498 * @param {Number/Array} x The page x or an array containing [x, y]
9499 * @param {Number} y The page y
9500 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9502 translatePoints : function(x, y){
9503 if(typeof x == 'object' || x instanceof Array){
9506 var p = this.getStyle('position');
9507 var o = this.getXY();
9509 var l = parseInt(this.getStyle('left'), 10);
9510 var t = parseInt(this.getStyle('top'), 10);
9513 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9516 t = (p == "relative") ? 0 : this.dom.offsetTop;
9519 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9523 * Returns the current scroll position of the element.
9524 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9526 getScroll : function(){
9527 var d = this.dom, doc = document;
9528 if(d == doc || d == doc.body){
9529 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9530 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9531 return {left: l, top: t};
9533 return {left: d.scrollLeft, top: d.scrollTop};
9538 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9539 * are convert to standard 6 digit hex color.
9540 * @param {String} attr The css attribute
9541 * @param {String} defaultValue The default value to use when a valid color isn't found
9542 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9545 getColor : function(attr, defaultValue, prefix){
9546 var v = this.getStyle(attr);
9547 if(!v || v == "transparent" || v == "inherit") {
9548 return defaultValue;
9550 var color = typeof prefix == "undefined" ? "#" : prefix;
9551 if(v.substr(0, 4) == "rgb("){
9552 var rvs = v.slice(4, v.length -1).split(",");
9553 for(var i = 0; i < 3; i++){
9554 var h = parseInt(rvs[i]).toString(16);
9561 if(v.substr(0, 1) == "#"){
9563 for(var i = 1; i < 4; i++){
9564 var c = v.charAt(i);
9567 }else if(v.length == 7){
9568 color += v.substr(1);
9572 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9576 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9577 * gradient background, rounded corners and a 4-way shadow.
9578 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9579 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9580 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9581 * @return {Roo.Element} this
9583 boxWrap : function(cls){
9584 cls = cls || 'x-box';
9585 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9586 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9591 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9592 * @param {String} namespace The namespace in which to look for the attribute
9593 * @param {String} name The attribute name
9594 * @return {String} The attribute value
9596 getAttributeNS : Roo.isIE ? function(ns, name){
9598 var type = typeof d[ns+":"+name];
9599 if(type != 'undefined' && type != 'unknown'){
9600 return d[ns+":"+name];
9603 } : function(ns, name){
9605 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9610 * Sets or Returns the value the dom attribute value
9611 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9612 * @param {String} value (optional) The value to set the attribute to
9613 * @return {String} The attribute value
9615 attr : function(name){
9616 if (arguments.length > 1) {
9617 this.dom.setAttribute(name, arguments[1]);
9618 return arguments[1];
9620 if (typeof(name) == 'object') {
9621 for(var i in name) {
9622 this.attr(i, name[i]);
9628 if (!this.dom.hasAttribute(name)) {
9631 return this.dom.getAttribute(name);
9638 var ep = El.prototype;
9641 * Appends an event handler (Shorthand for addListener)
9642 * @param {String} eventName The type of event to append
9643 * @param {Function} fn The method the event invokes
9644 * @param {Object} scope (optional) The scope (this object) of the fn
9645 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9648 ep.on = ep.addListener;
9650 ep.mon = ep.addListener;
9653 * Removes an event handler from this element (shorthand for removeListener)
9654 * @param {String} eventName the type of event to remove
9655 * @param {Function} fn the method the event invokes
9656 * @return {Roo.Element} this
9659 ep.un = ep.removeListener;
9662 * true to automatically adjust width and height settings for box-model issues (default to true)
9664 ep.autoBoxAdjust = true;
9667 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9670 El.addUnits = function(v, defaultUnit){
9671 if(v === "" || v == "auto"){
9674 if(v === undefined){
9677 if(typeof v == "number" || !El.unitPattern.test(v)){
9678 return v + (defaultUnit || 'px');
9683 // special markup used throughout Roo when box wrapping elements
9684 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>';
9686 * Visibility mode constant - Use visibility to hide element
9692 * Visibility mode constant - Use display to hide element
9698 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9699 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9700 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9712 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9713 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9714 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9715 * @return {Element} The Element object
9718 El.get = function(el){
9720 if(!el){ return null; }
9721 if(typeof el == "string"){ // element id
9722 if(!(elm = document.getElementById(el))){
9725 if(ex = El.cache[el]){
9728 ex = El.cache[el] = new El(elm);
9731 }else if(el.tagName){ // dom element
9735 if(ex = El.cache[id]){
9738 ex = El.cache[id] = new El(el);
9741 }else if(el instanceof El){
9743 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9744 // catch case where it hasn't been appended
9745 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9748 }else if(el.isComposite){
9750 }else if(el instanceof Array){
9751 return El.select(el);
9752 }else if(el == document){
9753 // create a bogus element object representing the document object
9755 var f = function(){};
9756 f.prototype = El.prototype;
9758 docEl.dom = document;
9766 El.uncache = function(el){
9767 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9769 delete El.cache[a[i].id || a[i]];
9775 // Garbage collection - uncache elements/purge listeners on orphaned elements
9776 // so we don't hold a reference and cause the browser to retain them
9777 El.garbageCollect = function(){
9778 if(!Roo.enableGarbageCollector){
9779 clearInterval(El.collectorThread);
9782 for(var eid in El.cache){
9783 var el = El.cache[eid], d = el.dom;
9784 // -------------------------------------------------------
9785 // Determining what is garbage:
9786 // -------------------------------------------------------
9788 // dom node is null, definitely garbage
9789 // -------------------------------------------------------
9791 // no parentNode == direct orphan, definitely garbage
9792 // -------------------------------------------------------
9793 // !d.offsetParent && !document.getElementById(eid)
9794 // display none elements have no offsetParent so we will
9795 // also try to look it up by it's id. However, check
9796 // offsetParent first so we don't do unneeded lookups.
9797 // This enables collection of elements that are not orphans
9798 // directly, but somewhere up the line they have an orphan
9800 // -------------------------------------------------------
9801 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9802 delete El.cache[eid];
9803 if(d && Roo.enableListenerCollection){
9809 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9813 El.Flyweight = function(dom){
9816 El.Flyweight.prototype = El.prototype;
9818 El._flyweights = {};
9820 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9821 * the dom node can be overwritten by other code.
9822 * @param {String/HTMLElement} el The dom node or id
9823 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9824 * prevent conflicts (e.g. internally Roo uses "_internal")
9826 * @return {Element} The shared Element object
9828 El.fly = function(el, named){
9829 named = named || '_global';
9830 el = Roo.getDom(el);
9834 if(!El._flyweights[named]){
9835 El._flyweights[named] = new El.Flyweight();
9837 El._flyweights[named].dom = el;
9838 return El._flyweights[named];
9842 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9843 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9844 * Shorthand of {@link Roo.Element#get}
9845 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9846 * @return {Element} The Element object
9852 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9853 * the dom node can be overwritten by other code.
9854 * Shorthand of {@link Roo.Element#fly}
9855 * @param {String/HTMLElement} el The dom node or id
9856 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9857 * prevent conflicts (e.g. internally Roo uses "_internal")
9859 * @return {Element} The shared Element object
9865 // speedy lookup for elements never to box adjust
9866 var noBoxAdjust = Roo.isStrict ? {
9869 input:1, select:1, textarea:1
9871 if(Roo.isIE || Roo.isGecko){
9872 noBoxAdjust['button'] = 1;
9876 Roo.EventManager.on(window, 'unload', function(){
9878 delete El._flyweights;
9886 Roo.Element.selectorFunction = Roo.DomQuery.select;
9889 Roo.Element.select = function(selector, unique, root){
9891 if(typeof selector == "string"){
9892 els = Roo.Element.selectorFunction(selector, root);
9893 }else if(selector.length !== undefined){
9896 throw "Invalid selector";
9898 if(unique === true){
9899 return new Roo.CompositeElement(els);
9901 return new Roo.CompositeElementLite(els);
9905 * Selects elements based on the passed CSS selector to enable working on them as 1.
9906 * @param {String/Array} selector The CSS selector or an array of elements
9907 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9908 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9909 * @return {CompositeElementLite/CompositeElement}
9913 Roo.select = Roo.Element.select;
9930 * Ext JS Library 1.1.1
9931 * Copyright(c) 2006-2007, Ext JS, LLC.
9933 * Originally Released Under LGPL - original licence link has changed is not relivant.
9936 * <script type="text/javascript">
9941 //Notifies Element that fx methods are available
9942 Roo.enableFx = true;
9946 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9947 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9948 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9949 * Element effects to work.</p><br/>
9951 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9952 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9953 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9954 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9955 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9956 * expected results and should be done with care.</p><br/>
9958 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9959 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9962 ----- -----------------------------
9963 tl The top left corner
9964 t The center of the top edge
9965 tr The top right corner
9966 l The center of the left edge
9967 r The center of the right edge
9968 bl The bottom left corner
9969 b The center of the bottom edge
9970 br The bottom right corner
9972 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9973 * below are common options that can be passed to any Fx method.</b>
9974 * @cfg {Function} callback A function called when the effect is finished
9975 * @cfg {Object} scope The scope of the effect function
9976 * @cfg {String} easing A valid Easing value for the effect
9977 * @cfg {String} afterCls A css class to apply after the effect
9978 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9979 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9980 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9981 * effects that end with the element being visually hidden, ignored otherwise)
9982 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9983 * a function which returns such a specification that will be applied to the Element after the effect finishes
9984 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9985 * @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
9986 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9990 * Slides the element into view. An anchor point can be optionally passed to set the point of
9991 * origin for the slide effect. This function automatically handles wrapping the element with
9992 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9995 // default: slide the element in from the top
9998 // custom: slide the element in from the right with a 2-second duration
9999 el.slideIn('r', { duration: 2 });
10001 // common config options shown with default values
10007 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10008 * @param {Object} options (optional) Object literal with any of the Fx config options
10009 * @return {Roo.Element} The Element
10011 slideIn : function(anchor, o){
10012 var el = this.getFxEl();
10015 el.queueFx(o, function(){
10017 anchor = anchor || "t";
10019 // fix display to visibility
10022 // restore values after effect
10023 var r = this.getFxRestore();
10024 var b = this.getBox();
10025 // fixed size for slide
10029 var wrap = this.fxWrap(r.pos, o, "hidden");
10031 var st = this.dom.style;
10032 st.visibility = "visible";
10033 st.position = "absolute";
10035 // clear out temp styles after slide and unwrap
10036 var after = function(){
10037 el.fxUnwrap(wrap, r.pos, o);
10038 st.width = r.width;
10039 st.height = r.height;
10042 // time to calc the positions
10043 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10045 switch(anchor.toLowerCase()){
10047 wrap.setSize(b.width, 0);
10048 st.left = st.bottom = "0";
10052 wrap.setSize(0, b.height);
10053 st.right = st.top = "0";
10057 wrap.setSize(0, b.height);
10058 wrap.setX(b.right);
10059 st.left = st.top = "0";
10060 a = {width: bw, points: pt};
10063 wrap.setSize(b.width, 0);
10064 wrap.setY(b.bottom);
10065 st.left = st.top = "0";
10066 a = {height: bh, points: pt};
10069 wrap.setSize(0, 0);
10070 st.right = st.bottom = "0";
10071 a = {width: bw, height: bh};
10074 wrap.setSize(0, 0);
10075 wrap.setY(b.y+b.height);
10076 st.right = st.top = "0";
10077 a = {width: bw, height: bh, points: pt};
10080 wrap.setSize(0, 0);
10081 wrap.setXY([b.right, b.bottom]);
10082 st.left = st.top = "0";
10083 a = {width: bw, height: bh, points: pt};
10086 wrap.setSize(0, 0);
10087 wrap.setX(b.x+b.width);
10088 st.left = st.bottom = "0";
10089 a = {width: bw, height: bh, points: pt};
10092 this.dom.style.visibility = "visible";
10095 arguments.callee.anim = wrap.fxanim(a,
10105 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10106 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10107 * 'hidden') but block elements will still take up space in the document. The element must be removed
10108 * from the DOM using the 'remove' config option if desired. This function automatically handles
10109 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10112 // default: slide the element out to the top
10115 // custom: slide the element out to the right with a 2-second duration
10116 el.slideOut('r', { duration: 2 });
10118 // common config options shown with default values
10126 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10127 * @param {Object} options (optional) Object literal with any of the Fx config options
10128 * @return {Roo.Element} The Element
10130 slideOut : function(anchor, o){
10131 var el = this.getFxEl();
10134 el.queueFx(o, function(){
10136 anchor = anchor || "t";
10138 // restore values after effect
10139 var r = this.getFxRestore();
10141 var b = this.getBox();
10142 // fixed size for slide
10146 var wrap = this.fxWrap(r.pos, o, "visible");
10148 var st = this.dom.style;
10149 st.visibility = "visible";
10150 st.position = "absolute";
10154 var after = function(){
10156 el.setDisplayed(false);
10161 el.fxUnwrap(wrap, r.pos, o);
10163 st.width = r.width;
10164 st.height = r.height;
10169 var a, zero = {to: 0};
10170 switch(anchor.toLowerCase()){
10172 st.left = st.bottom = "0";
10173 a = {height: zero};
10176 st.right = st.top = "0";
10180 st.left = st.top = "0";
10181 a = {width: zero, points: {to:[b.right, b.y]}};
10184 st.left = st.top = "0";
10185 a = {height: zero, points: {to:[b.x, b.bottom]}};
10188 st.right = st.bottom = "0";
10189 a = {width: zero, height: zero};
10192 st.right = st.top = "0";
10193 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10196 st.left = st.top = "0";
10197 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10200 st.left = st.bottom = "0";
10201 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10205 arguments.callee.anim = wrap.fxanim(a,
10215 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10216 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10217 * The element must be removed from the DOM using the 'remove' config option if desired.
10223 // common config options shown with default values
10231 * @param {Object} options (optional) Object literal with any of the Fx config options
10232 * @return {Roo.Element} The Element
10234 puff : function(o){
10235 var el = this.getFxEl();
10238 el.queueFx(o, function(){
10239 this.clearOpacity();
10242 // restore values after effect
10243 var r = this.getFxRestore();
10244 var st = this.dom.style;
10246 var after = function(){
10248 el.setDisplayed(false);
10255 el.setPositioning(r.pos);
10256 st.width = r.width;
10257 st.height = r.height;
10262 var width = this.getWidth();
10263 var height = this.getHeight();
10265 arguments.callee.anim = this.fxanim({
10266 width : {to: this.adjustWidth(width * 2)},
10267 height : {to: this.adjustHeight(height * 2)},
10268 points : {by: [-(width * .5), -(height * .5)]},
10270 fontSize: {to:200, unit: "%"}
10281 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10282 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10283 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10289 // all config options shown with default values
10297 * @param {Object} options (optional) Object literal with any of the Fx config options
10298 * @return {Roo.Element} The Element
10300 switchOff : function(o){
10301 var el = this.getFxEl();
10304 el.queueFx(o, function(){
10305 this.clearOpacity();
10308 // restore values after effect
10309 var r = this.getFxRestore();
10310 var st = this.dom.style;
10312 var after = function(){
10314 el.setDisplayed(false);
10320 el.setPositioning(r.pos);
10321 st.width = r.width;
10322 st.height = r.height;
10327 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10328 this.clearOpacity();
10332 points:{by:[0, this.getHeight() * .5]}
10333 }, o, 'motion', 0.3, 'easeIn', after);
10334 }).defer(100, this);
10341 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10342 * changed using the "attr" config option) and then fading back to the original color. If no original
10343 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10346 // default: highlight background to yellow
10349 // custom: highlight foreground text to blue for 2 seconds
10350 el.highlight("0000ff", { attr: 'color', duration: 2 });
10352 // common config options shown with default values
10353 el.highlight("ffff9c", {
10354 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10355 endColor: (current color) or "ffffff",
10360 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10361 * @param {Object} options (optional) Object literal with any of the Fx config options
10362 * @return {Roo.Element} The Element
10364 highlight : function(color, o){
10365 var el = this.getFxEl();
10368 el.queueFx(o, function(){
10369 color = color || "ffff9c";
10370 attr = o.attr || "backgroundColor";
10372 this.clearOpacity();
10375 var origColor = this.getColor(attr);
10376 var restoreColor = this.dom.style[attr];
10377 endColor = (o.endColor || origColor) || "ffffff";
10379 var after = function(){
10380 el.dom.style[attr] = restoreColor;
10385 a[attr] = {from: color, to: endColor};
10386 arguments.callee.anim = this.fxanim(a,
10396 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10399 // default: a single light blue ripple
10402 // custom: 3 red ripples lasting 3 seconds total
10403 el.frame("ff0000", 3, { duration: 3 });
10405 // common config options shown with default values
10406 el.frame("C3DAF9", 1, {
10407 duration: 1 //duration of entire animation (not each individual ripple)
10408 // Note: Easing is not configurable and will be ignored if included
10411 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10412 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10413 * @param {Object} options (optional) Object literal with any of the Fx config options
10414 * @return {Roo.Element} The Element
10416 frame : function(color, count, o){
10417 var el = this.getFxEl();
10420 el.queueFx(o, function(){
10421 color = color || "#C3DAF9";
10422 if(color.length == 6){
10423 color = "#" + color;
10425 count = count || 1;
10426 duration = o.duration || 1;
10429 var b = this.getBox();
10430 var animFn = function(){
10431 var proxy = this.createProxy({
10434 visbility:"hidden",
10435 position:"absolute",
10436 "z-index":"35000", // yee haw
10437 border:"0px solid " + color
10440 var scale = Roo.isBorderBox ? 2 : 1;
10442 top:{from:b.y, to:b.y - 20},
10443 left:{from:b.x, to:b.x - 20},
10444 borderWidth:{from:0, to:10},
10445 opacity:{from:1, to:0},
10446 height:{from:b.height, to:(b.height + (20*scale))},
10447 width:{from:b.width, to:(b.width + (20*scale))}
10448 }, duration, function(){
10452 animFn.defer((duration/2)*1000, this);
10463 * Creates a pause before any subsequent queued effects begin. If there are
10464 * no effects queued after the pause it will have no effect.
10469 * @param {Number} seconds The length of time to pause (in seconds)
10470 * @return {Roo.Element} The Element
10472 pause : function(seconds){
10473 var el = this.getFxEl();
10476 el.queueFx(o, function(){
10477 setTimeout(function(){
10479 }, seconds * 1000);
10485 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10486 * using the "endOpacity" config option.
10489 // default: fade in from opacity 0 to 100%
10492 // custom: fade in from opacity 0 to 75% over 2 seconds
10493 el.fadeIn({ endOpacity: .75, duration: 2});
10495 // common config options shown with default values
10497 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10502 * @param {Object} options (optional) Object literal with any of the Fx config options
10503 * @return {Roo.Element} The Element
10505 fadeIn : function(o){
10506 var el = this.getFxEl();
10508 el.queueFx(o, function(){
10509 this.setOpacity(0);
10511 this.dom.style.visibility = 'visible';
10512 var to = o.endOpacity || 1;
10513 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10514 o, null, .5, "easeOut", function(){
10516 this.clearOpacity();
10525 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10526 * using the "endOpacity" config option.
10529 // default: fade out from the element's current opacity to 0
10532 // custom: fade out from the element's current opacity to 25% over 2 seconds
10533 el.fadeOut({ endOpacity: .25, duration: 2});
10535 // common config options shown with default values
10537 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10544 * @param {Object} options (optional) Object literal with any of the Fx config options
10545 * @return {Roo.Element} The Element
10547 fadeOut : function(o){
10548 var el = this.getFxEl();
10550 el.queueFx(o, function(){
10551 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10552 o, null, .5, "easeOut", function(){
10553 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10554 this.dom.style.display = "none";
10556 this.dom.style.visibility = "hidden";
10558 this.clearOpacity();
10566 * Animates the transition of an element's dimensions from a starting height/width
10567 * to an ending height/width.
10570 // change height and width to 100x100 pixels
10571 el.scale(100, 100);
10573 // common config options shown with default values. The height and width will default to
10574 // the element's existing values if passed as null.
10577 [element's height], {
10582 * @param {Number} width The new width (pass undefined to keep the original width)
10583 * @param {Number} height The new height (pass undefined to keep the original height)
10584 * @param {Object} options (optional) Object literal with any of the Fx config options
10585 * @return {Roo.Element} The Element
10587 scale : function(w, h, o){
10588 this.shift(Roo.apply({}, o, {
10596 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10597 * Any of these properties not specified in the config object will not be changed. This effect
10598 * requires that at least one new dimension, position or opacity setting must be passed in on
10599 * the config object in order for the function to have any effect.
10602 // slide the element horizontally to x position 200 while changing the height and opacity
10603 el.shift({ x: 200, height: 50, opacity: .8 });
10605 // common config options shown with default values.
10607 width: [element's width],
10608 height: [element's height],
10609 x: [element's x position],
10610 y: [element's y position],
10611 opacity: [element's opacity],
10616 * @param {Object} options Object literal with any of the Fx config options
10617 * @return {Roo.Element} The Element
10619 shift : function(o){
10620 var el = this.getFxEl();
10622 el.queueFx(o, function(){
10623 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10624 if(w !== undefined){
10625 a.width = {to: this.adjustWidth(w)};
10627 if(h !== undefined){
10628 a.height = {to: this.adjustHeight(h)};
10630 if(x !== undefined || y !== undefined){
10632 x !== undefined ? x : this.getX(),
10633 y !== undefined ? y : this.getY()
10636 if(op !== undefined){
10637 a.opacity = {to: op};
10639 if(o.xy !== undefined){
10640 a.points = {to: o.xy};
10642 arguments.callee.anim = this.fxanim(a,
10643 o, 'motion', .35, "easeOut", function(){
10651 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10652 * ending point of the effect.
10655 // default: slide the element downward while fading out
10658 // custom: slide the element out to the right with a 2-second duration
10659 el.ghost('r', { duration: 2 });
10661 // common config options shown with default values
10669 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10670 * @param {Object} options (optional) Object literal with any of the Fx config options
10671 * @return {Roo.Element} The Element
10673 ghost : function(anchor, o){
10674 var el = this.getFxEl();
10677 el.queueFx(o, function(){
10678 anchor = anchor || "b";
10680 // restore values after effect
10681 var r = this.getFxRestore();
10682 var w = this.getWidth(),
10683 h = this.getHeight();
10685 var st = this.dom.style;
10687 var after = function(){
10689 el.setDisplayed(false);
10695 el.setPositioning(r.pos);
10696 st.width = r.width;
10697 st.height = r.height;
10702 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10703 switch(anchor.toLowerCase()){
10730 arguments.callee.anim = this.fxanim(a,
10740 * Ensures that all effects queued after syncFx is called on the element are
10741 * run concurrently. This is the opposite of {@link #sequenceFx}.
10742 * @return {Roo.Element} The Element
10744 syncFx : function(){
10745 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10754 * Ensures that all effects queued after sequenceFx is called on the element are
10755 * run in sequence. This is the opposite of {@link #syncFx}.
10756 * @return {Roo.Element} The Element
10758 sequenceFx : function(){
10759 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10761 concurrent : false,
10768 nextFx : function(){
10769 var ef = this.fxQueue[0];
10776 * Returns true if the element has any effects actively running or queued, else returns false.
10777 * @return {Boolean} True if element has active effects, else false
10779 hasActiveFx : function(){
10780 return this.fxQueue && this.fxQueue[0];
10784 * Stops any running effects and clears the element's internal effects queue if it contains
10785 * any additional effects that haven't started yet.
10786 * @return {Roo.Element} The Element
10788 stopFx : function(){
10789 if(this.hasActiveFx()){
10790 var cur = this.fxQueue[0];
10791 if(cur && cur.anim && cur.anim.isAnimated()){
10792 this.fxQueue = [cur]; // clear out others
10793 cur.anim.stop(true);
10800 beforeFx : function(o){
10801 if(this.hasActiveFx() && !o.concurrent){
10812 * Returns true if the element is currently blocking so that no other effect can be queued
10813 * until this effect is finished, else returns false if blocking is not set. This is commonly
10814 * used to ensure that an effect initiated by a user action runs to completion prior to the
10815 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10816 * @return {Boolean} True if blocking, else false
10818 hasFxBlock : function(){
10819 var q = this.fxQueue;
10820 return q && q[0] && q[0].block;
10824 queueFx : function(o, fn){
10828 if(!this.hasFxBlock()){
10829 Roo.applyIf(o, this.fxDefaults);
10831 var run = this.beforeFx(o);
10832 fn.block = o.block;
10833 this.fxQueue.push(fn);
10845 fxWrap : function(pos, o, vis){
10847 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10850 wrapXY = this.getXY();
10852 var div = document.createElement("div");
10853 div.style.visibility = vis;
10854 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10855 wrap.setPositioning(pos);
10856 if(wrap.getStyle("position") == "static"){
10857 wrap.position("relative");
10859 this.clearPositioning('auto');
10861 wrap.dom.appendChild(this.dom);
10863 wrap.setXY(wrapXY);
10870 fxUnwrap : function(wrap, pos, o){
10871 this.clearPositioning();
10872 this.setPositioning(pos);
10874 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10880 getFxRestore : function(){
10881 var st = this.dom.style;
10882 return {pos: this.getPositioning(), width: st.width, height : st.height};
10886 afterFx : function(o){
10888 this.applyStyles(o.afterStyle);
10891 this.addClass(o.afterCls);
10893 if(o.remove === true){
10896 Roo.callback(o.callback, o.scope, [this]);
10898 this.fxQueue.shift();
10904 getFxEl : function(){ // support for composite element fx
10905 return Roo.get(this.dom);
10909 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10910 animType = animType || 'run';
10912 var anim = Roo.lib.Anim[animType](
10914 (opt.duration || defaultDur) || .35,
10915 (opt.easing || defaultEase) || 'easeOut',
10917 Roo.callback(cb, this);
10926 // backwords compat
10927 Roo.Fx.resize = Roo.Fx.scale;
10929 //When included, Roo.Fx is automatically applied to Element so that all basic
10930 //effects are available directly via the Element API
10931 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10933 * Ext JS Library 1.1.1
10934 * Copyright(c) 2006-2007, Ext JS, LLC.
10936 * Originally Released Under LGPL - original licence link has changed is not relivant.
10939 * <script type="text/javascript">
10944 * @class Roo.CompositeElement
10945 * Standard composite class. Creates a Roo.Element for every element in the collection.
10947 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10948 * actions will be performed on all the elements in this collection.</b>
10950 * All methods return <i>this</i> and can be chained.
10952 var els = Roo.select("#some-el div.some-class", true);
10953 // or select directly from an existing element
10954 var el = Roo.get('some-el');
10955 el.select('div.some-class', true);
10957 els.setWidth(100); // all elements become 100 width
10958 els.hide(true); // all elements fade out and hide
10960 els.setWidth(100).hide(true);
10963 Roo.CompositeElement = function(els){
10964 this.elements = [];
10965 this.addElements(els);
10967 Roo.CompositeElement.prototype = {
10969 addElements : function(els){
10970 if(!els) return this;
10971 if(typeof els == "string"){
10972 els = Roo.Element.selectorFunction(els);
10974 var yels = this.elements;
10975 var index = yels.length-1;
10976 for(var i = 0, len = els.length; i < len; i++) {
10977 yels[++index] = Roo.get(els[i]);
10983 * Clears this composite and adds the elements returned by the passed selector.
10984 * @param {String/Array} els A string CSS selector, an array of elements or an element
10985 * @return {CompositeElement} this
10987 fill : function(els){
10988 this.elements = [];
10994 * Filters this composite to only elements that match the passed selector.
10995 * @param {String} selector A string CSS selector
10996 * @param {Boolean} inverse return inverse filter (not matches)
10997 * @return {CompositeElement} this
10999 filter : function(selector, inverse){
11001 inverse = inverse || false;
11002 this.each(function(el){
11003 var match = inverse ? !el.is(selector) : el.is(selector);
11005 els[els.length] = el.dom;
11012 invoke : function(fn, args){
11013 var els = this.elements;
11014 for(var i = 0, len = els.length; i < len; i++) {
11015 Roo.Element.prototype[fn].apply(els[i], args);
11020 * Adds elements to this composite.
11021 * @param {String/Array} els A string CSS selector, an array of elements or an element
11022 * @return {CompositeElement} this
11024 add : function(els){
11025 if(typeof els == "string"){
11026 this.addElements(Roo.Element.selectorFunction(els));
11027 }else if(els.length !== undefined){
11028 this.addElements(els);
11030 this.addElements([els]);
11035 * Calls the passed function passing (el, this, index) for each element in this composite.
11036 * @param {Function} fn The function to call
11037 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11038 * @return {CompositeElement} this
11040 each : function(fn, scope){
11041 var els = this.elements;
11042 for(var i = 0, len = els.length; i < len; i++){
11043 if(fn.call(scope || els[i], els[i], this, i) === false) {
11051 * Returns the Element object at the specified index
11052 * @param {Number} index
11053 * @return {Roo.Element}
11055 item : function(index){
11056 return this.elements[index] || null;
11060 * Returns the first Element
11061 * @return {Roo.Element}
11063 first : function(){
11064 return this.item(0);
11068 * Returns the last Element
11069 * @return {Roo.Element}
11072 return this.item(this.elements.length-1);
11076 * Returns the number of elements in this composite
11079 getCount : function(){
11080 return this.elements.length;
11084 * Returns true if this composite contains the passed element
11087 contains : function(el){
11088 return this.indexOf(el) !== -1;
11092 * Returns true if this composite contains the passed element
11095 indexOf : function(el){
11096 return this.elements.indexOf(Roo.get(el));
11101 * Removes the specified element(s).
11102 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11103 * or an array of any of those.
11104 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11105 * @return {CompositeElement} this
11107 removeElement : function(el, removeDom){
11108 if(el instanceof Array){
11109 for(var i = 0, len = el.length; i < len; i++){
11110 this.removeElement(el[i]);
11114 var index = typeof el == 'number' ? el : this.indexOf(el);
11117 var d = this.elements[index];
11121 d.parentNode.removeChild(d);
11124 this.elements.splice(index, 1);
11130 * Replaces the specified element with the passed element.
11131 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11133 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11134 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11135 * @return {CompositeElement} this
11137 replaceElement : function(el, replacement, domReplace){
11138 var index = typeof el == 'number' ? el : this.indexOf(el);
11141 this.elements[index].replaceWith(replacement);
11143 this.elements.splice(index, 1, Roo.get(replacement))
11150 * Removes all elements.
11152 clear : function(){
11153 this.elements = [];
11157 Roo.CompositeElement.createCall = function(proto, fnName){
11158 if(!proto[fnName]){
11159 proto[fnName] = function(){
11160 return this.invoke(fnName, arguments);
11164 for(var fnName in Roo.Element.prototype){
11165 if(typeof Roo.Element.prototype[fnName] == "function"){
11166 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11172 * Ext JS Library 1.1.1
11173 * Copyright(c) 2006-2007, Ext JS, LLC.
11175 * Originally Released Under LGPL - original licence link has changed is not relivant.
11178 * <script type="text/javascript">
11182 * @class Roo.CompositeElementLite
11183 * @extends Roo.CompositeElement
11184 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11186 var els = Roo.select("#some-el div.some-class");
11187 // or select directly from an existing element
11188 var el = Roo.get('some-el');
11189 el.select('div.some-class');
11191 els.setWidth(100); // all elements become 100 width
11192 els.hide(true); // all elements fade out and hide
11194 els.setWidth(100).hide(true);
11195 </code></pre><br><br>
11196 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11197 * actions will be performed on all the elements in this collection.</b>
11199 Roo.CompositeElementLite = function(els){
11200 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11201 this.el = new Roo.Element.Flyweight();
11203 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11204 addElements : function(els){
11206 if(els instanceof Array){
11207 this.elements = this.elements.concat(els);
11209 var yels = this.elements;
11210 var index = yels.length-1;
11211 for(var i = 0, len = els.length; i < len; i++) {
11212 yels[++index] = els[i];
11218 invoke : function(fn, args){
11219 var els = this.elements;
11221 for(var i = 0, len = els.length; i < len; i++) {
11223 Roo.Element.prototype[fn].apply(el, args);
11228 * Returns a flyweight Element of the dom element object at the specified index
11229 * @param {Number} index
11230 * @return {Roo.Element}
11232 item : function(index){
11233 if(!this.elements[index]){
11236 this.el.dom = this.elements[index];
11240 // fixes scope with flyweight
11241 addListener : function(eventName, handler, scope, opt){
11242 var els = this.elements;
11243 for(var i = 0, len = els.length; i < len; i++) {
11244 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11250 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11251 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11252 * a reference to the dom node, use el.dom.</b>
11253 * @param {Function} fn The function to call
11254 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11255 * @return {CompositeElement} this
11257 each : function(fn, scope){
11258 var els = this.elements;
11260 for(var i = 0, len = els.length; i < len; i++){
11262 if(fn.call(scope || el, el, this, i) === false){
11269 indexOf : function(el){
11270 return this.elements.indexOf(Roo.getDom(el));
11273 replaceElement : function(el, replacement, domReplace){
11274 var index = typeof el == 'number' ? el : this.indexOf(el);
11276 replacement = Roo.getDom(replacement);
11278 var d = this.elements[index];
11279 d.parentNode.insertBefore(replacement, d);
11280 d.parentNode.removeChild(d);
11282 this.elements.splice(index, 1, replacement);
11287 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11291 * Ext JS Library 1.1.1
11292 * Copyright(c) 2006-2007, Ext JS, LLC.
11294 * Originally Released Under LGPL - original licence link has changed is not relivant.
11297 * <script type="text/javascript">
11303 * @class Roo.data.Connection
11304 * @extends Roo.util.Observable
11305 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11306 * either to a configured URL, or to a URL specified at request time.<br><br>
11308 * Requests made by this class are asynchronous, and will return immediately. No data from
11309 * the server will be available to the statement immediately following the {@link #request} call.
11310 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11312 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11313 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11314 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11315 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11316 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11317 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11318 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11319 * standard DOM methods.
11321 * @param {Object} config a configuration object.
11323 Roo.data.Connection = function(config){
11324 Roo.apply(this, config);
11327 * @event beforerequest
11328 * Fires before a network request is made to retrieve a data object.
11329 * @param {Connection} conn This Connection object.
11330 * @param {Object} options The options config object passed to the {@link #request} method.
11332 "beforerequest" : true,
11334 * @event requestcomplete
11335 * Fires if the request was successfully completed.
11336 * @param {Connection} conn This Connection object.
11337 * @param {Object} response The XHR object containing the response data.
11338 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11339 * @param {Object} options The options config object passed to the {@link #request} method.
11341 "requestcomplete" : true,
11343 * @event requestexception
11344 * Fires if an error HTTP status was returned from the server.
11345 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11346 * @param {Connection} conn This Connection object.
11347 * @param {Object} response The XHR object containing the response data.
11348 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11349 * @param {Object} options The options config object passed to the {@link #request} method.
11351 "requestexception" : true
11353 Roo.data.Connection.superclass.constructor.call(this);
11356 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11358 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11361 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11362 * extra parameters to each request made by this object. (defaults to undefined)
11365 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11366 * to each request made by this object. (defaults to undefined)
11369 * @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)
11372 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11376 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11382 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11385 disableCaching: true,
11388 * Sends an HTTP request to a remote server.
11389 * @param {Object} options An object which may contain the following properties:<ul>
11390 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11391 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11392 * request, a url encoded string or a function to call to get either.</li>
11393 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11394 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11395 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11396 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11397 * <li>options {Object} The parameter to the request call.</li>
11398 * <li>success {Boolean} True if the request succeeded.</li>
11399 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11401 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11402 * The callback is passed the following parameters:<ul>
11403 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11404 * <li>options {Object} The parameter to the request call.</li>
11406 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11407 * The callback is passed the following parameters:<ul>
11408 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11409 * <li>options {Object} The parameter to the request call.</li>
11411 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11412 * for the callback function. Defaults to the browser window.</li>
11413 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11414 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11415 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11416 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11417 * params for the post data. Any params will be appended to the URL.</li>
11418 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11420 * @return {Number} transactionId
11422 request : function(o){
11423 if(this.fireEvent("beforerequest", this, o) !== false){
11426 if(typeof p == "function"){
11427 p = p.call(o.scope||window, o);
11429 if(typeof p == "object"){
11430 p = Roo.urlEncode(o.params);
11432 if(this.extraParams){
11433 var extras = Roo.urlEncode(this.extraParams);
11434 p = p ? (p + '&' + extras) : extras;
11437 var url = o.url || this.url;
11438 if(typeof url == 'function'){
11439 url = url.call(o.scope||window, o);
11443 var form = Roo.getDom(o.form);
11444 url = url || form.action;
11446 var enctype = form.getAttribute("enctype");
11447 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11448 return this.doFormUpload(o, p, url);
11450 var f = Roo.lib.Ajax.serializeForm(form);
11451 p = p ? (p + '&' + f) : f;
11454 var hs = o.headers;
11455 if(this.defaultHeaders){
11456 hs = Roo.apply(hs || {}, this.defaultHeaders);
11463 success: this.handleResponse,
11464 failure: this.handleFailure,
11466 argument: {options: o},
11467 timeout : o.timeout || this.timeout
11470 var method = o.method||this.method||(p ? "POST" : "GET");
11472 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11473 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11476 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11480 }else if(this.autoAbort !== false){
11484 if((method == 'GET' && p) || o.xmlData){
11485 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11488 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11489 return this.transId;
11491 Roo.callback(o.callback, o.scope, [o, null, null]);
11497 * Determine whether this object has a request outstanding.
11498 * @param {Number} transactionId (Optional) defaults to the last transaction
11499 * @return {Boolean} True if there is an outstanding request.
11501 isLoading : function(transId){
11503 return Roo.lib.Ajax.isCallInProgress(transId);
11505 return this.transId ? true : false;
11510 * Aborts any outstanding request.
11511 * @param {Number} transactionId (Optional) defaults to the last transaction
11513 abort : function(transId){
11514 if(transId || this.isLoading()){
11515 Roo.lib.Ajax.abort(transId || this.transId);
11520 handleResponse : function(response){
11521 this.transId = false;
11522 var options = response.argument.options;
11523 response.argument = options ? options.argument : null;
11524 this.fireEvent("requestcomplete", this, response, options);
11525 Roo.callback(options.success, options.scope, [response, options]);
11526 Roo.callback(options.callback, options.scope, [options, true, response]);
11530 handleFailure : function(response, e){
11531 this.transId = false;
11532 var options = response.argument.options;
11533 response.argument = options ? options.argument : null;
11534 this.fireEvent("requestexception", this, response, options, e);
11535 Roo.callback(options.failure, options.scope, [response, options]);
11536 Roo.callback(options.callback, options.scope, [options, false, response]);
11540 doFormUpload : function(o, ps, url){
11542 var frame = document.createElement('iframe');
11545 frame.className = 'x-hidden';
11547 frame.src = Roo.SSL_SECURE_URL;
11549 document.body.appendChild(frame);
11552 document.frames[id].name = id;
11555 var form = Roo.getDom(o.form);
11557 form.method = 'POST';
11558 form.enctype = form.encoding = 'multipart/form-data';
11564 if(ps){ // add dynamic params
11566 ps = Roo.urlDecode(ps, false);
11568 if(ps.hasOwnProperty(k)){
11569 hd = document.createElement('input');
11570 hd.type = 'hidden';
11573 form.appendChild(hd);
11580 var r = { // bogus response object
11585 r.argument = o ? o.argument : null;
11590 doc = frame.contentWindow.document;
11592 doc = (frame.contentDocument || window.frames[id].document);
11594 if(doc && doc.body){
11595 r.responseText = doc.body.innerHTML;
11597 if(doc && doc.XMLDocument){
11598 r.responseXML = doc.XMLDocument;
11600 r.responseXML = doc;
11607 Roo.EventManager.removeListener(frame, 'load', cb, this);
11609 this.fireEvent("requestcomplete", this, r, o);
11610 Roo.callback(o.success, o.scope, [r, o]);
11611 Roo.callback(o.callback, o.scope, [o, true, r]);
11613 setTimeout(function(){document.body.removeChild(frame);}, 100);
11616 Roo.EventManager.on(frame, 'load', cb, this);
11619 if(hiddens){ // remove dynamic params
11620 for(var i = 0, len = hiddens.length; i < len; i++){
11621 form.removeChild(hiddens[i]);
11628 * Ext JS Library 1.1.1
11629 * Copyright(c) 2006-2007, Ext JS, LLC.
11631 * Originally Released Under LGPL - original licence link has changed is not relivant.
11634 * <script type="text/javascript">
11638 * Global Ajax request class.
11641 * @extends Roo.data.Connection
11644 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11645 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11646 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11647 * @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)
11648 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11649 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11650 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11652 Roo.Ajax = new Roo.data.Connection({
11661 * Serialize the passed form into a url encoded string
11663 * @param {String/HTMLElement} form
11666 serializeForm : function(form){
11667 return Roo.lib.Ajax.serializeForm(form);
11671 * Ext JS Library 1.1.1
11672 * Copyright(c) 2006-2007, Ext JS, LLC.
11674 * Originally Released Under LGPL - original licence link has changed is not relivant.
11677 * <script type="text/javascript">
11682 * @class Roo.UpdateManager
11683 * @extends Roo.util.Observable
11684 * Provides AJAX-style update for Element object.<br><br>
11687 * // Get it from a Roo.Element object
11688 * var el = Roo.get("foo");
11689 * var mgr = el.getUpdateManager();
11690 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11692 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11694 * // or directly (returns the same UpdateManager instance)
11695 * var mgr = new Roo.UpdateManager("myElementId");
11696 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11697 * mgr.on("update", myFcnNeedsToKnow);
11699 // short handed call directly from the element object
11700 Roo.get("foo").load({
11704 text: "Loading Foo..."
11708 * Create new UpdateManager directly.
11709 * @param {String/HTMLElement/Roo.Element} el The element to update
11710 * @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).
11712 Roo.UpdateManager = function(el, forceNew){
11714 if(!forceNew && el.updateManager){
11715 return el.updateManager;
11718 * The Element object
11719 * @type Roo.Element
11723 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11726 this.defaultUrl = null;
11730 * @event beforeupdate
11731 * Fired before an update is made, return false from your handler and the update is cancelled.
11732 * @param {Roo.Element} el
11733 * @param {String/Object/Function} url
11734 * @param {String/Object} params
11736 "beforeupdate": true,
11739 * Fired after successful update is made.
11740 * @param {Roo.Element} el
11741 * @param {Object} oResponseObject The response Object
11746 * Fired on update failure.
11747 * @param {Roo.Element} el
11748 * @param {Object} oResponseObject The response Object
11752 var d = Roo.UpdateManager.defaults;
11754 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11757 this.sslBlankUrl = d.sslBlankUrl;
11759 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11762 this.disableCaching = d.disableCaching;
11764 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11767 this.indicatorText = d.indicatorText;
11769 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11772 this.showLoadIndicator = d.showLoadIndicator;
11774 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11777 this.timeout = d.timeout;
11780 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11783 this.loadScripts = d.loadScripts;
11786 * Transaction object of current executing transaction
11788 this.transaction = null;
11793 this.autoRefreshProcId = null;
11795 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11798 this.refreshDelegate = this.refresh.createDelegate(this);
11800 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11803 this.updateDelegate = this.update.createDelegate(this);
11805 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11808 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11812 this.successDelegate = this.processSuccess.createDelegate(this);
11816 this.failureDelegate = this.processFailure.createDelegate(this);
11818 if(!this.renderer){
11820 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11822 this.renderer = new Roo.UpdateManager.BasicRenderer();
11825 Roo.UpdateManager.superclass.constructor.call(this);
11828 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11830 * Get the Element this UpdateManager is bound to
11831 * @return {Roo.Element} The element
11833 getEl : function(){
11837 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11838 * @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:
11841 url: "your-url.php",<br/>
11842 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11843 callback: yourFunction,<br/>
11844 scope: yourObject, //(optional scope) <br/>
11845 discardUrl: false, <br/>
11846 nocache: false,<br/>
11847 text: "Loading...",<br/>
11849 scripts: false<br/>
11852 * The only required property is url. The optional properties nocache, text and scripts
11853 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11854 * @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}
11855 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11856 * @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.
11858 update : function(url, params, callback, discardUrl){
11859 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11860 var method = this.method,
11862 if(typeof url == "object"){ // must be config object
11865 params = params || cfg.params;
11866 callback = callback || cfg.callback;
11867 discardUrl = discardUrl || cfg.discardUrl;
11868 if(callback && cfg.scope){
11869 callback = callback.createDelegate(cfg.scope);
11871 if(typeof cfg.method != "undefined"){method = cfg.method;};
11872 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11873 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11874 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11875 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11877 this.showLoading();
11879 this.defaultUrl = url;
11881 if(typeof url == "function"){
11882 url = url.call(this);
11885 method = method || (params ? "POST" : "GET");
11886 if(method == "GET"){
11887 url = this.prepareUrl(url);
11890 var o = Roo.apply(cfg ||{}, {
11893 success: this.successDelegate,
11894 failure: this.failureDelegate,
11895 callback: undefined,
11896 timeout: (this.timeout*1000),
11897 argument: {"url": url, "form": null, "callback": callback, "params": params}
11899 Roo.log("updated manager called with timeout of " + o.timeout);
11900 this.transaction = Roo.Ajax.request(o);
11905 * 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.
11906 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11907 * @param {String/HTMLElement} form The form Id or form element
11908 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11909 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11910 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11912 formUpdate : function(form, url, reset, callback){
11913 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11914 if(typeof url == "function"){
11915 url = url.call(this);
11917 form = Roo.getDom(form);
11918 this.transaction = Roo.Ajax.request({
11921 success: this.successDelegate,
11922 failure: this.failureDelegate,
11923 timeout: (this.timeout*1000),
11924 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11926 this.showLoading.defer(1, this);
11931 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11932 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11934 refresh : function(callback){
11935 if(this.defaultUrl == null){
11938 this.update(this.defaultUrl, null, callback, true);
11942 * Set this element to auto refresh.
11943 * @param {Number} interval How often to update (in seconds).
11944 * @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)
11945 * @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}
11946 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11947 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11949 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11951 this.update(url || this.defaultUrl, params, callback, true);
11953 if(this.autoRefreshProcId){
11954 clearInterval(this.autoRefreshProcId);
11956 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11960 * Stop auto refresh on this element.
11962 stopAutoRefresh : function(){
11963 if(this.autoRefreshProcId){
11964 clearInterval(this.autoRefreshProcId);
11965 delete this.autoRefreshProcId;
11969 isAutoRefreshing : function(){
11970 return this.autoRefreshProcId ? true : false;
11973 * Called to update the element to "Loading" state. Override to perform custom action.
11975 showLoading : function(){
11976 if(this.showLoadIndicator){
11977 this.el.update(this.indicatorText);
11982 * Adds unique parameter to query string if disableCaching = true
11985 prepareUrl : function(url){
11986 if(this.disableCaching){
11987 var append = "_dc=" + (new Date().getTime());
11988 if(url.indexOf("?") !== -1){
11989 url += "&" + append;
11991 url += "?" + append;
12000 processSuccess : function(response){
12001 this.transaction = null;
12002 if(response.argument.form && response.argument.reset){
12003 try{ // put in try/catch since some older FF releases had problems with this
12004 response.argument.form.reset();
12007 if(this.loadScripts){
12008 this.renderer.render(this.el, response, this,
12009 this.updateComplete.createDelegate(this, [response]));
12011 this.renderer.render(this.el, response, this);
12012 this.updateComplete(response);
12016 updateComplete : function(response){
12017 this.fireEvent("update", this.el, response);
12018 if(typeof response.argument.callback == "function"){
12019 response.argument.callback(this.el, true, response);
12026 processFailure : function(response){
12027 this.transaction = null;
12028 this.fireEvent("failure", this.el, response);
12029 if(typeof response.argument.callback == "function"){
12030 response.argument.callback(this.el, false, response);
12035 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12036 * @param {Object} renderer The object implementing the render() method
12038 setRenderer : function(renderer){
12039 this.renderer = renderer;
12042 getRenderer : function(){
12043 return this.renderer;
12047 * Set the defaultUrl used for updates
12048 * @param {String/Function} defaultUrl The url or a function to call to get the url
12050 setDefaultUrl : function(defaultUrl){
12051 this.defaultUrl = defaultUrl;
12055 * Aborts the executing transaction
12057 abort : function(){
12058 if(this.transaction){
12059 Roo.Ajax.abort(this.transaction);
12064 * Returns true if an update is in progress
12065 * @return {Boolean}
12067 isUpdating : function(){
12068 if(this.transaction){
12069 return Roo.Ajax.isLoading(this.transaction);
12076 * @class Roo.UpdateManager.defaults
12077 * @static (not really - but it helps the doc tool)
12078 * The defaults collection enables customizing the default properties of UpdateManager
12080 Roo.UpdateManager.defaults = {
12082 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12088 * True to process scripts by default (Defaults to false).
12091 loadScripts : false,
12094 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12097 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12099 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12102 disableCaching : false,
12104 * Whether to show indicatorText when loading (Defaults to true).
12107 showLoadIndicator : true,
12109 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12112 indicatorText : '<div class="loading-indicator">Loading...</div>'
12116 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12118 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12119 * @param {String/HTMLElement/Roo.Element} el The element to update
12120 * @param {String} url The url
12121 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12122 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12125 * @member Roo.UpdateManager
12127 Roo.UpdateManager.updateElement = function(el, url, params, options){
12128 var um = Roo.get(el, true).getUpdateManager();
12129 Roo.apply(um, options);
12130 um.update(url, params, options ? options.callback : null);
12132 // alias for backwards compat
12133 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12135 * @class Roo.UpdateManager.BasicRenderer
12136 * Default Content renderer. Updates the elements innerHTML with the responseText.
12138 Roo.UpdateManager.BasicRenderer = function(){};
12140 Roo.UpdateManager.BasicRenderer.prototype = {
12142 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12143 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12144 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12145 * @param {Roo.Element} el The element being rendered
12146 * @param {Object} response The YUI Connect response object
12147 * @param {UpdateManager} updateManager The calling update manager
12148 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12150 render : function(el, response, updateManager, callback){
12151 el.update(response.responseText, updateManager.loadScripts, callback);
12157 * (c)) Alan Knowles
12163 * @class Roo.DomTemplate
12164 * @extends Roo.Template
12165 * An effort at a dom based template engine..
12167 * Similar to XTemplate, except it uses dom parsing to create the template..
12169 * Supported features:
12174 {a_variable} - output encoded.
12175 {a_variable.format:("Y-m-d")} - call a method on the variable
12176 {a_variable:raw} - unencoded output
12177 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12178 {a_variable:this.method_on_template(...)} - call a method on the template object.
12183 <div roo-for="a_variable or condition.."></div>
12184 <div roo-if="a_variable or condition"></div>
12185 <div roo-exec="some javascript"></div>
12186 <div roo-name="named_template"></div>
12191 Roo.DomTemplate = function()
12193 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12200 Roo.extend(Roo.DomTemplate, Roo.Template, {
12202 * id counter for sub templates.
12206 * flag to indicate if dom parser is inside a pre,
12207 * it will strip whitespace if not.
12212 * The various sub templates
12220 * basic tag replacing syntax
12223 * // you can fake an object call by doing this
12227 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12228 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12230 iterChild : function (node, method) {
12232 var oldPre = this.inPre;
12233 if (node.tagName == 'PRE') {
12236 for( var i = 0; i < node.childNodes.length; i++) {
12237 method.call(this, node.childNodes[i]);
12239 this.inPre = oldPre;
12245 * compile the template
12247 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12250 compile: function()
12254 // covert the html into DOM...
12258 doc = document.implementation.createHTMLDocument("");
12259 doc.documentElement.innerHTML = this.html ;
12260 div = doc.documentElement;
12262 // old IE... - nasty -- it causes all sorts of issues.. with
12263 // images getting pulled from server..
12264 div = document.createElement('div');
12265 div.innerHTML = this.html;
12267 //doc.documentElement.innerHTML = htmlBody
12273 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12275 var tpls = this.tpls;
12277 // create a top level template from the snippet..
12279 //Roo.log(div.innerHTML);
12286 body : div.innerHTML,
12299 Roo.each(tpls, function(tp){
12300 this.compileTpl(tp);
12301 this.tpls[tp.id] = tp;
12304 this.master = tpls[0];
12310 compileNode : function(node, istop) {
12315 // skip anything not a tag..
12316 if (node.nodeType != 1) {
12317 if (node.nodeType == 3 && !this.inPre) {
12318 // reduce white space..
12319 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12342 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12343 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12344 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12345 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12351 // just itterate children..
12352 this.iterChild(node,this.compileNode);
12355 tpl.uid = this.id++;
12356 tpl.value = node.getAttribute('roo-' + tpl.attr);
12357 node.removeAttribute('roo-'+ tpl.attr);
12358 if (tpl.attr != 'name') {
12359 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12360 node.parentNode.replaceChild(placeholder, node);
12363 var placeholder = document.createElement('span');
12364 placeholder.className = 'roo-tpl-' + tpl.value;
12365 node.parentNode.replaceChild(placeholder, node);
12368 // parent now sees '{domtplXXXX}
12369 this.iterChild(node,this.compileNode);
12371 // we should now have node body...
12372 var div = document.createElement('div');
12373 div.appendChild(node);
12375 // this has the unfortunate side effect of converting tagged attributes
12376 // eg. href="{...}" into %7C...%7D
12377 // this has been fixed by searching for those combo's although it's a bit hacky..
12380 tpl.body = div.innerHTML;
12387 switch (tpl.value) {
12388 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12389 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12390 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12395 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12399 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12403 tpl.id = tpl.value; // replace non characters???
12409 this.tpls.push(tpl);
12419 * Compile a segment of the template into a 'sub-template'
12425 compileTpl : function(tpl)
12427 var fm = Roo.util.Format;
12428 var useF = this.disableFormats !== true;
12430 var sep = Roo.isGecko ? "+\n" : ",\n";
12432 var undef = function(str) {
12433 Roo.debug && Roo.log("Property not found :" + str);
12437 //Roo.log(tpl.body);
12441 var fn = function(m, lbrace, name, format, args)
12444 //Roo.log(arguments);
12445 args = args ? args.replace(/\\'/g,"'") : args;
12446 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12447 if (typeof(format) == 'undefined') {
12448 format = 'htmlEncode';
12450 if (format == 'raw' ) {
12454 if(name.substr(0, 6) == 'domtpl'){
12455 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12458 // build an array of options to determine if value is undefined..
12460 // basically get 'xxxx.yyyy' then do
12461 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12462 // (function () { Roo.log("Property not found"); return ''; })() :
12467 Roo.each(name.split('.'), function(st) {
12468 lookfor += (lookfor.length ? '.': '') + st;
12469 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12472 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12475 if(format && useF){
12477 args = args ? ',' + args : "";
12479 if(format.substr(0, 5) != "this."){
12480 format = "fm." + format + '(';
12482 format = 'this.call("'+ format.substr(5) + '", ';
12486 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12489 if (args && args.length) {
12490 // called with xxyx.yuu:(test,test)
12492 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12494 // raw.. - :raw modifier..
12495 return "'"+ sep + udef_st + name + ")"+sep+"'";
12499 // branched to use + in gecko and [].join() in others
12501 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12502 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12505 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12506 body.push(tpl.body.replace(/(\r\n|\n)/g,
12507 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12508 body.push("'].join('');};};");
12509 body = body.join('');
12512 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12514 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12521 * same as applyTemplate, except it's done to one of the subTemplates
12522 * when using named templates, you can do:
12524 * var str = pl.applySubTemplate('your-name', values);
12527 * @param {Number} id of the template
12528 * @param {Object} values to apply to template
12529 * @param {Object} parent (normaly the instance of this object)
12531 applySubTemplate : function(id, values, parent)
12535 var t = this.tpls[id];
12539 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12540 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12544 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12551 if(t.execCall && t.execCall.call(this, values, parent)){
12555 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12561 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12562 parent = t.target ? values : parent;
12563 if(t.forCall && vs instanceof Array){
12565 for(var i = 0, len = vs.length; i < len; i++){
12567 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12569 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12571 //Roo.log(t.compiled);
12575 return buf.join('');
12578 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12583 return t.compiled.call(this, vs, parent);
12585 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12587 //Roo.log(t.compiled);
12595 applyTemplate : function(values){
12596 return this.master.compiled.call(this, values, {});
12597 //var s = this.subs;
12600 apply : function(){
12601 return this.applyTemplate.apply(this, arguments);
12606 Roo.DomTemplate.from = function(el){
12607 el = Roo.getDom(el);
12608 return new Roo.Domtemplate(el.value || el.innerHTML);
12611 * Ext JS Library 1.1.1
12612 * Copyright(c) 2006-2007, Ext JS, LLC.
12614 * Originally Released Under LGPL - original licence link has changed is not relivant.
12617 * <script type="text/javascript">
12621 * @class Roo.util.DelayedTask
12622 * Provides a convenient method of performing setTimeout where a new
12623 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12624 * You can use this class to buffer
12625 * the keypress events for a certain number of milliseconds, and perform only if they stop
12626 * for that amount of time.
12627 * @constructor The parameters to this constructor serve as defaults and are not required.
12628 * @param {Function} fn (optional) The default function to timeout
12629 * @param {Object} scope (optional) The default scope of that timeout
12630 * @param {Array} args (optional) The default Array of arguments
12632 Roo.util.DelayedTask = function(fn, scope, args){
12633 var id = null, d, t;
12635 var call = function(){
12636 var now = new Date().getTime();
12640 fn.apply(scope, args || []);
12644 * Cancels any pending timeout and queues a new one
12645 * @param {Number} delay The milliseconds to delay
12646 * @param {Function} newFn (optional) Overrides function passed to constructor
12647 * @param {Object} newScope (optional) Overrides scope passed to constructor
12648 * @param {Array} newArgs (optional) Overrides args passed to constructor
12650 this.delay = function(delay, newFn, newScope, newArgs){
12651 if(id && delay != d){
12655 t = new Date().getTime();
12657 scope = newScope || scope;
12658 args = newArgs || args;
12660 id = setInterval(call, d);
12665 * Cancel the last queued timeout
12667 this.cancel = function(){
12675 * Ext JS Library 1.1.1
12676 * Copyright(c) 2006-2007, Ext JS, LLC.
12678 * Originally Released Under LGPL - original licence link has changed is not relivant.
12681 * <script type="text/javascript">
12685 Roo.util.TaskRunner = function(interval){
12686 interval = interval || 10;
12687 var tasks = [], removeQueue = [];
12689 var running = false;
12691 var stopThread = function(){
12697 var startThread = function(){
12700 id = setInterval(runTasks, interval);
12704 var removeTask = function(task){
12705 removeQueue.push(task);
12711 var runTasks = function(){
12712 if(removeQueue.length > 0){
12713 for(var i = 0, len = removeQueue.length; i < len; i++){
12714 tasks.remove(removeQueue[i]);
12717 if(tasks.length < 1){
12722 var now = new Date().getTime();
12723 for(var i = 0, len = tasks.length; i < len; ++i){
12725 var itime = now - t.taskRunTime;
12726 if(t.interval <= itime){
12727 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12728 t.taskRunTime = now;
12729 if(rt === false || t.taskRunCount === t.repeat){
12734 if(t.duration && t.duration <= (now - t.taskStartTime)){
12741 * Queues a new task.
12742 * @param {Object} task
12744 this.start = function(task){
12746 task.taskStartTime = new Date().getTime();
12747 task.taskRunTime = 0;
12748 task.taskRunCount = 0;
12753 this.stop = function(task){
12758 this.stopAll = function(){
12760 for(var i = 0, len = tasks.length; i < len; i++){
12761 if(tasks[i].onStop){
12770 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12772 * Ext JS Library 1.1.1
12773 * Copyright(c) 2006-2007, Ext JS, LLC.
12775 * Originally Released Under LGPL - original licence link has changed is not relivant.
12778 * <script type="text/javascript">
12783 * @class Roo.util.MixedCollection
12784 * @extends Roo.util.Observable
12785 * A Collection class that maintains both numeric indexes and keys and exposes events.
12787 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12788 * collection (defaults to false)
12789 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12790 * and return the key value for that item. This is used when available to look up the key on items that
12791 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12792 * equivalent to providing an implementation for the {@link #getKey} method.
12794 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12802 * Fires when the collection is cleared.
12807 * Fires when an item is added to the collection.
12808 * @param {Number} index The index at which the item was added.
12809 * @param {Object} o The item added.
12810 * @param {String} key The key associated with the added item.
12815 * Fires when an item is replaced in the collection.
12816 * @param {String} key he key associated with the new added.
12817 * @param {Object} old The item being replaced.
12818 * @param {Object} new The new item.
12823 * Fires when an item is removed from the collection.
12824 * @param {Object} o The item being removed.
12825 * @param {String} key (optional) The key associated with the removed item.
12830 this.allowFunctions = allowFunctions === true;
12832 this.getKey = keyFn;
12834 Roo.util.MixedCollection.superclass.constructor.call(this);
12837 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12838 allowFunctions : false,
12841 * Adds an item to the collection.
12842 * @param {String} key The key to associate with the item
12843 * @param {Object} o The item to add.
12844 * @return {Object} The item added.
12846 add : function(key, o){
12847 if(arguments.length == 1){
12849 key = this.getKey(o);
12851 if(typeof key == "undefined" || key === null){
12853 this.items.push(o);
12854 this.keys.push(null);
12856 var old = this.map[key];
12858 return this.replace(key, o);
12861 this.items.push(o);
12863 this.keys.push(key);
12865 this.fireEvent("add", this.length-1, o, key);
12870 * MixedCollection has a generic way to fetch keys if you implement getKey.
12873 var mc = new Roo.util.MixedCollection();
12874 mc.add(someEl.dom.id, someEl);
12875 mc.add(otherEl.dom.id, otherEl);
12879 var mc = new Roo.util.MixedCollection();
12880 mc.getKey = function(el){
12886 // or via the constructor
12887 var mc = new Roo.util.MixedCollection(false, function(el){
12893 * @param o {Object} The item for which to find the key.
12894 * @return {Object} The key for the passed item.
12896 getKey : function(o){
12901 * Replaces an item in the collection.
12902 * @param {String} key The key associated with the item to replace, or the item to replace.
12903 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12904 * @return {Object} The new item.
12906 replace : function(key, o){
12907 if(arguments.length == 1){
12909 key = this.getKey(o);
12911 var old = this.item(key);
12912 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12913 return this.add(key, o);
12915 var index = this.indexOfKey(key);
12916 this.items[index] = o;
12918 this.fireEvent("replace", key, old, o);
12923 * Adds all elements of an Array or an Object to the collection.
12924 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12925 * an Array of values, each of which are added to the collection.
12927 addAll : function(objs){
12928 if(arguments.length > 1 || objs instanceof Array){
12929 var args = arguments.length > 1 ? arguments : objs;
12930 for(var i = 0, len = args.length; i < len; i++){
12934 for(var key in objs){
12935 if(this.allowFunctions || typeof objs[key] != "function"){
12936 this.add(key, objs[key]);
12943 * Executes the specified function once for every item in the collection, passing each
12944 * item as the first and only parameter. returning false from the function will stop the iteration.
12945 * @param {Function} fn The function to execute for each item.
12946 * @param {Object} scope (optional) The scope in which to execute the function.
12948 each : function(fn, scope){
12949 var items = [].concat(this.items); // each safe for removal
12950 for(var i = 0, len = items.length; i < len; i++){
12951 if(fn.call(scope || items[i], items[i], i, len) === false){
12958 * Executes the specified function once for every key in the collection, passing each
12959 * key, and its associated item as the first two parameters.
12960 * @param {Function} fn The function to execute for each item.
12961 * @param {Object} scope (optional) The scope in which to execute the function.
12963 eachKey : function(fn, scope){
12964 for(var i = 0, len = this.keys.length; i < len; i++){
12965 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12970 * Returns the first item in the collection which elicits a true return value from the
12971 * passed selection function.
12972 * @param {Function} fn The selection function to execute for each item.
12973 * @param {Object} scope (optional) The scope in which to execute the function.
12974 * @return {Object} The first item in the collection which returned true from the selection function.
12976 find : function(fn, scope){
12977 for(var i = 0, len = this.items.length; i < len; i++){
12978 if(fn.call(scope || window, this.items[i], this.keys[i])){
12979 return this.items[i];
12986 * Inserts an item at the specified index in the collection.
12987 * @param {Number} index The index to insert the item at.
12988 * @param {String} key The key to associate with the new item, or the item itself.
12989 * @param {Object} o (optional) If the second parameter was a key, the new item.
12990 * @return {Object} The item inserted.
12992 insert : function(index, key, o){
12993 if(arguments.length == 2){
12995 key = this.getKey(o);
12997 if(index >= this.length){
12998 return this.add(key, o);
13001 this.items.splice(index, 0, o);
13002 if(typeof key != "undefined" && key != null){
13005 this.keys.splice(index, 0, key);
13006 this.fireEvent("add", index, o, key);
13011 * Removed an item from the collection.
13012 * @param {Object} o The item to remove.
13013 * @return {Object} The item removed.
13015 remove : function(o){
13016 return this.removeAt(this.indexOf(o));
13020 * Remove an item from a specified index in the collection.
13021 * @param {Number} index The index within the collection of the item to remove.
13023 removeAt : function(index){
13024 if(index < this.length && index >= 0){
13026 var o = this.items[index];
13027 this.items.splice(index, 1);
13028 var key = this.keys[index];
13029 if(typeof key != "undefined"){
13030 delete this.map[key];
13032 this.keys.splice(index, 1);
13033 this.fireEvent("remove", o, key);
13038 * Removed an item associated with the passed key fom the collection.
13039 * @param {String} key The key of the item to remove.
13041 removeKey : function(key){
13042 return this.removeAt(this.indexOfKey(key));
13046 * Returns the number of items in the collection.
13047 * @return {Number} the number of items in the collection.
13049 getCount : function(){
13050 return this.length;
13054 * Returns index within the collection of the passed Object.
13055 * @param {Object} o The item to find the index of.
13056 * @return {Number} index of the item.
13058 indexOf : function(o){
13059 if(!this.items.indexOf){
13060 for(var i = 0, len = this.items.length; i < len; i++){
13061 if(this.items[i] == o) return i;
13065 return this.items.indexOf(o);
13070 * Returns index within the collection of the passed key.
13071 * @param {String} key The key to find the index of.
13072 * @return {Number} index of the key.
13074 indexOfKey : function(key){
13075 if(!this.keys.indexOf){
13076 for(var i = 0, len = this.keys.length; i < len; i++){
13077 if(this.keys[i] == key) return i;
13081 return this.keys.indexOf(key);
13086 * Returns the item associated with the passed key OR index. Key has priority over index.
13087 * @param {String/Number} key The key or index of the item.
13088 * @return {Object} The item associated with the passed key.
13090 item : function(key){
13091 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13092 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13096 * Returns the item at the specified index.
13097 * @param {Number} index The index of the item.
13100 itemAt : function(index){
13101 return this.items[index];
13105 * Returns the item associated with the passed key.
13106 * @param {String/Number} key The key of the item.
13107 * @return {Object} The item associated with the passed key.
13109 key : function(key){
13110 return this.map[key];
13114 * Returns true if the collection contains the passed Object as an item.
13115 * @param {Object} o The Object to look for in the collection.
13116 * @return {Boolean} True if the collection contains the Object as an item.
13118 contains : function(o){
13119 return this.indexOf(o) != -1;
13123 * Returns true if the collection contains the passed Object as a key.
13124 * @param {String} key The key to look for in the collection.
13125 * @return {Boolean} True if the collection contains the Object as a key.
13127 containsKey : function(key){
13128 return typeof this.map[key] != "undefined";
13132 * Removes all items from the collection.
13134 clear : function(){
13139 this.fireEvent("clear");
13143 * Returns the first item in the collection.
13144 * @return {Object} the first item in the collection..
13146 first : function(){
13147 return this.items[0];
13151 * Returns the last item in the collection.
13152 * @return {Object} the last item in the collection..
13155 return this.items[this.length-1];
13158 _sort : function(property, dir, fn){
13159 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13160 fn = fn || function(a, b){
13163 var c = [], k = this.keys, items = this.items;
13164 for(var i = 0, len = items.length; i < len; i++){
13165 c[c.length] = {key: k[i], value: items[i], index: i};
13167 c.sort(function(a, b){
13168 var v = fn(a[property], b[property]) * dsc;
13170 v = (a.index < b.index ? -1 : 1);
13174 for(var i = 0, len = c.length; i < len; i++){
13175 items[i] = c[i].value;
13178 this.fireEvent("sort", this);
13182 * Sorts this collection with the passed comparison function
13183 * @param {String} direction (optional) "ASC" or "DESC"
13184 * @param {Function} fn (optional) comparison function
13186 sort : function(dir, fn){
13187 this._sort("value", dir, fn);
13191 * Sorts this collection by keys
13192 * @param {String} direction (optional) "ASC" or "DESC"
13193 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13195 keySort : function(dir, fn){
13196 this._sort("key", dir, fn || function(a, b){
13197 return String(a).toUpperCase()-String(b).toUpperCase();
13202 * Returns a range of items in this collection
13203 * @param {Number} startIndex (optional) defaults to 0
13204 * @param {Number} endIndex (optional) default to the last item
13205 * @return {Array} An array of items
13207 getRange : function(start, end){
13208 var items = this.items;
13209 if(items.length < 1){
13212 start = start || 0;
13213 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13216 for(var i = start; i <= end; i++) {
13217 r[r.length] = items[i];
13220 for(var i = start; i >= end; i--) {
13221 r[r.length] = items[i];
13228 * Filter the <i>objects</i> in this collection by a specific property.
13229 * Returns a new collection that has been filtered.
13230 * @param {String} property A property on your objects
13231 * @param {String/RegExp} value Either string that the property values
13232 * should start with or a RegExp to test against the property
13233 * @return {MixedCollection} The new filtered collection
13235 filter : function(property, value){
13236 if(!value.exec){ // not a regex
13237 value = String(value);
13238 if(value.length == 0){
13239 return this.clone();
13241 value = new RegExp("^" + Roo.escapeRe(value), "i");
13243 return this.filterBy(function(o){
13244 return o && value.test(o[property]);
13249 * Filter by a function. * Returns a new collection that has been filtered.
13250 * The passed function will be called with each
13251 * object in the collection. If the function returns true, the value is included
13252 * otherwise it is filtered.
13253 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13254 * @param {Object} scope (optional) The scope of the function (defaults to this)
13255 * @return {MixedCollection} The new filtered collection
13257 filterBy : function(fn, scope){
13258 var r = new Roo.util.MixedCollection();
13259 r.getKey = this.getKey;
13260 var k = this.keys, it = this.items;
13261 for(var i = 0, len = it.length; i < len; i++){
13262 if(fn.call(scope||this, it[i], k[i])){
13263 r.add(k[i], it[i]);
13270 * Creates a duplicate of this collection
13271 * @return {MixedCollection}
13273 clone : function(){
13274 var r = new Roo.util.MixedCollection();
13275 var k = this.keys, it = this.items;
13276 for(var i = 0, len = it.length; i < len; i++){
13277 r.add(k[i], it[i]);
13279 r.getKey = this.getKey;
13284 * Returns the item associated with the passed key or index.
13286 * @param {String/Number} key The key or index of the item.
13287 * @return {Object} The item associated with the passed key.
13289 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13291 * Ext JS Library 1.1.1
13292 * Copyright(c) 2006-2007, Ext JS, LLC.
13294 * Originally Released Under LGPL - original licence link has changed is not relivant.
13297 * <script type="text/javascript">
13300 * @class Roo.util.JSON
13301 * Modified version of Douglas Crockford"s json.js that doesn"t
13302 * mess with the Object prototype
13303 * http://www.json.org/js.html
13306 Roo.util.JSON = new (function(){
13307 var useHasOwn = {}.hasOwnProperty ? true : false;
13309 // crashes Safari in some instances
13310 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13312 var pad = function(n) {
13313 return n < 10 ? "0" + n : n;
13326 var encodeString = function(s){
13327 if (/["\\\x00-\x1f]/.test(s)) {
13328 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13333 c = b.charCodeAt();
13335 Math.floor(c / 16).toString(16) +
13336 (c % 16).toString(16);
13339 return '"' + s + '"';
13342 var encodeArray = function(o){
13343 var a = ["["], b, i, l = o.length, v;
13344 for (i = 0; i < l; i += 1) {
13346 switch (typeof v) {
13355 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13363 var encodeDate = function(o){
13364 return '"' + o.getFullYear() + "-" +
13365 pad(o.getMonth() + 1) + "-" +
13366 pad(o.getDate()) + "T" +
13367 pad(o.getHours()) + ":" +
13368 pad(o.getMinutes()) + ":" +
13369 pad(o.getSeconds()) + '"';
13373 * Encodes an Object, Array or other value
13374 * @param {Mixed} o The variable to encode
13375 * @return {String} The JSON string
13377 this.encode = function(o)
13379 // should this be extended to fully wrap stringify..
13381 if(typeof o == "undefined" || o === null){
13383 }else if(o instanceof Array){
13384 return encodeArray(o);
13385 }else if(o instanceof Date){
13386 return encodeDate(o);
13387 }else if(typeof o == "string"){
13388 return encodeString(o);
13389 }else if(typeof o == "number"){
13390 return isFinite(o) ? String(o) : "null";
13391 }else if(typeof o == "boolean"){
13394 var a = ["{"], b, i, v;
13396 if(!useHasOwn || o.hasOwnProperty(i)) {
13398 switch (typeof v) {
13407 a.push(this.encode(i), ":",
13408 v === null ? "null" : this.encode(v));
13419 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13420 * @param {String} json The JSON string
13421 * @return {Object} The resulting object
13423 this.decode = function(json){
13425 return /** eval:var:json */ eval("(" + json + ')');
13429 * Shorthand for {@link Roo.util.JSON#encode}
13430 * @member Roo encode
13432 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13434 * Shorthand for {@link Roo.util.JSON#decode}
13435 * @member Roo decode
13437 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13440 * Ext JS Library 1.1.1
13441 * Copyright(c) 2006-2007, Ext JS, LLC.
13443 * Originally Released Under LGPL - original licence link has changed is not relivant.
13446 * <script type="text/javascript">
13450 * @class Roo.util.Format
13451 * Reusable data formatting functions
13454 Roo.util.Format = function(){
13455 var trimRe = /^\s+|\s+$/g;
13458 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13459 * @param {String} value The string to truncate
13460 * @param {Number} length The maximum length to allow before truncating
13461 * @return {String} The converted text
13463 ellipsis : function(value, len){
13464 if(value && value.length > len){
13465 return value.substr(0, len-3)+"...";
13471 * Checks a reference and converts it to empty string if it is undefined
13472 * @param {Mixed} value Reference to check
13473 * @return {Mixed} Empty string if converted, otherwise the original value
13475 undef : function(value){
13476 return typeof value != "undefined" ? value : "";
13480 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13481 * @param {String} value The string to encode
13482 * @return {String} The encoded text
13484 htmlEncode : function(value){
13485 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13489 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13490 * @param {String} value The string to decode
13491 * @return {String} The decoded text
13493 htmlDecode : function(value){
13494 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13498 * Trims any whitespace from either side of a string
13499 * @param {String} value The text to trim
13500 * @return {String} The trimmed text
13502 trim : function(value){
13503 return String(value).replace(trimRe, "");
13507 * Returns a substring from within an original string
13508 * @param {String} value The original text
13509 * @param {Number} start The start index of the substring
13510 * @param {Number} length The length of the substring
13511 * @return {String} The substring
13513 substr : function(value, start, length){
13514 return String(value).substr(start, length);
13518 * Converts a string to all lower case letters
13519 * @param {String} value The text to convert
13520 * @return {String} The converted text
13522 lowercase : function(value){
13523 return String(value).toLowerCase();
13527 * Converts a string to all upper case letters
13528 * @param {String} value The text to convert
13529 * @return {String} The converted text
13531 uppercase : function(value){
13532 return String(value).toUpperCase();
13536 * Converts the first character only of a string to upper case
13537 * @param {String} value The text to convert
13538 * @return {String} The converted text
13540 capitalize : function(value){
13541 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13545 call : function(value, fn){
13546 if(arguments.length > 2){
13547 var args = Array.prototype.slice.call(arguments, 2);
13548 args.unshift(value);
13550 return /** eval:var:value */ eval(fn).apply(window, args);
13552 /** eval:var:value */
13553 return /** eval:var:value */ eval(fn).call(window, value);
13559 * safer version of Math.toFixed..??/
13560 * @param {Number/String} value The numeric value to format
13561 * @param {Number/String} value Decimal places
13562 * @return {String} The formatted currency string
13564 toFixed : function(v, n)
13566 // why not use to fixed - precision is buggered???
13568 return Math.round(v-0);
13570 var fact = Math.pow(10,n+1);
13571 v = (Math.round((v-0)*fact))/fact;
13572 var z = (''+fact).substring(2);
13573 if (v == Math.floor(v)) {
13574 return Math.floor(v) + '.' + z;
13577 // now just padd decimals..
13578 var ps = String(v).split('.');
13579 var fd = (ps[1] + z);
13580 var r = fd.substring(0,n);
13581 var rm = fd.substring(n);
13583 return ps[0] + '.' + r;
13585 r*=1; // turn it into a number;
13587 if (String(r).length != n) {
13590 r = String(r).substring(1); // chop the end off.
13593 return ps[0] + '.' + r;
13598 * Format a number as US currency
13599 * @param {Number/String} value The numeric value to format
13600 * @return {String} The formatted currency string
13602 usMoney : function(v){
13603 return '$' + Roo.util.Format.number(v);
13608 * eventually this should probably emulate php's number_format
13609 * @param {Number/String} value The numeric value to format
13610 * @param {Number} decimals number of decimal places
13611 * @return {String} The formatted currency string
13613 number : function(v,decimals)
13615 // multiply and round.
13616 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13617 var mul = Math.pow(10, decimals);
13618 var zero = String(mul).substring(1);
13619 v = (Math.round((v-0)*mul))/mul;
13621 // if it's '0' number.. then
13623 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13625 var ps = v.split('.');
13629 var r = /(\d+)(\d{3})/;
13631 while (r.test(whole)) {
13632 whole = whole.replace(r, '$1' + ',' + '$2');
13638 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13639 // does not have decimals
13640 (decimals ? ('.' + zero) : '');
13643 return whole + sub ;
13647 * Parse a value into a formatted date using the specified format pattern.
13648 * @param {Mixed} value The value to format
13649 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13650 * @return {String} The formatted date string
13652 date : function(v, format){
13656 if(!(v instanceof Date)){
13657 v = new Date(Date.parse(v));
13659 return v.dateFormat(format || Roo.util.Format.defaults.date);
13663 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13664 * @param {String} format Any valid date format string
13665 * @return {Function} The date formatting function
13667 dateRenderer : function(format){
13668 return function(v){
13669 return Roo.util.Format.date(v, format);
13674 stripTagsRE : /<\/?[^>]+>/gi,
13677 * Strips all HTML tags
13678 * @param {Mixed} value The text from which to strip tags
13679 * @return {String} The stripped text
13681 stripTags : function(v){
13682 return !v ? v : String(v).replace(this.stripTagsRE, "");
13686 Roo.util.Format.defaults = {
13690 * Ext JS Library 1.1.1
13691 * Copyright(c) 2006-2007, Ext JS, LLC.
13693 * Originally Released Under LGPL - original licence link has changed is not relivant.
13696 * <script type="text/javascript">
13703 * @class Roo.MasterTemplate
13704 * @extends Roo.Template
13705 * Provides a template that can have child templates. The syntax is:
13707 var t = new Roo.MasterTemplate(
13708 '<select name="{name}">',
13709 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13712 t.add('options', {value: 'foo', text: 'bar'});
13713 // or you can add multiple child elements in one shot
13714 t.addAll('options', [
13715 {value: 'foo', text: 'bar'},
13716 {value: 'foo2', text: 'bar2'},
13717 {value: 'foo3', text: 'bar3'}
13719 // then append, applying the master template values
13720 t.append('my-form', {name: 'my-select'});
13722 * A name attribute for the child template is not required if you have only one child
13723 * template or you want to refer to them by index.
13725 Roo.MasterTemplate = function(){
13726 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13727 this.originalHtml = this.html;
13729 var m, re = this.subTemplateRe;
13732 while(m = re.exec(this.html)){
13733 var name = m[1], content = m[2];
13738 tpl : new Roo.Template(content)
13741 st[name] = st[subIndex];
13743 st[subIndex].tpl.compile();
13744 st[subIndex].tpl.call = this.call.createDelegate(this);
13747 this.subCount = subIndex;
13750 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13752 * The regular expression used to match sub templates
13756 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13759 * Applies the passed values to a child template.
13760 * @param {String/Number} name (optional) The name or index of the child template
13761 * @param {Array/Object} values The values to be applied to the template
13762 * @return {MasterTemplate} this
13764 add : function(name, values){
13765 if(arguments.length == 1){
13766 values = arguments[0];
13769 var s = this.subs[name];
13770 s.buffer[s.buffer.length] = s.tpl.apply(values);
13775 * Applies all the passed values to a child template.
13776 * @param {String/Number} name (optional) The name or index of the child template
13777 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13778 * @param {Boolean} reset (optional) True to reset the template first
13779 * @return {MasterTemplate} this
13781 fill : function(name, values, reset){
13783 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13791 for(var i = 0, len = values.length; i < len; i++){
13792 this.add(name, values[i]);
13798 * Resets the template for reuse
13799 * @return {MasterTemplate} this
13801 reset : function(){
13803 for(var i = 0; i < this.subCount; i++){
13809 applyTemplate : function(values){
13811 var replaceIndex = -1;
13812 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13813 return s[++replaceIndex].buffer.join("");
13815 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13818 apply : function(){
13819 return this.applyTemplate.apply(this, arguments);
13822 compile : function(){return this;}
13826 * Alias for fill().
13829 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13831 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13832 * var tpl = Roo.MasterTemplate.from('element-id');
13833 * @param {String/HTMLElement} el
13834 * @param {Object} config
13837 Roo.MasterTemplate.from = function(el, config){
13838 el = Roo.getDom(el);
13839 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13842 * Ext JS Library 1.1.1
13843 * Copyright(c) 2006-2007, Ext JS, LLC.
13845 * Originally Released Under LGPL - original licence link has changed is not relivant.
13848 * <script type="text/javascript">
13853 * @class Roo.util.CSS
13854 * Utility class for manipulating CSS rules
13857 Roo.util.CSS = function(){
13859 var doc = document;
13861 var camelRe = /(-[a-z])/gi;
13862 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13866 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13867 * tag and appended to the HEAD of the document.
13868 * @param {String|Object} cssText The text containing the css rules
13869 * @param {String} id An id to add to the stylesheet for later removal
13870 * @return {StyleSheet}
13872 createStyleSheet : function(cssText, id){
13874 var head = doc.getElementsByTagName("head")[0];
13875 var nrules = doc.createElement("style");
13876 nrules.setAttribute("type", "text/css");
13878 nrules.setAttribute("id", id);
13880 if (typeof(cssText) != 'string') {
13881 // support object maps..
13882 // not sure if this a good idea..
13883 // perhaps it should be merged with the general css handling
13884 // and handle js style props.
13885 var cssTextNew = [];
13886 for(var n in cssText) {
13888 for(var k in cssText[n]) {
13889 citems.push( k + ' : ' +cssText[n][k] + ';' );
13891 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13894 cssText = cssTextNew.join("\n");
13900 head.appendChild(nrules);
13901 ss = nrules.styleSheet;
13902 ss.cssText = cssText;
13905 nrules.appendChild(doc.createTextNode(cssText));
13907 nrules.cssText = cssText;
13909 head.appendChild(nrules);
13910 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13912 this.cacheStyleSheet(ss);
13917 * Removes a style or link tag by id
13918 * @param {String} id The id of the tag
13920 removeStyleSheet : function(id){
13921 var existing = doc.getElementById(id);
13923 existing.parentNode.removeChild(existing);
13928 * Dynamically swaps an existing stylesheet reference for a new one
13929 * @param {String} id The id of an existing link tag to remove
13930 * @param {String} url The href of the new stylesheet to include
13932 swapStyleSheet : function(id, url){
13933 this.removeStyleSheet(id);
13934 var ss = doc.createElement("link");
13935 ss.setAttribute("rel", "stylesheet");
13936 ss.setAttribute("type", "text/css");
13937 ss.setAttribute("id", id);
13938 ss.setAttribute("href", url);
13939 doc.getElementsByTagName("head")[0].appendChild(ss);
13943 * Refresh the rule cache if you have dynamically added stylesheets
13944 * @return {Object} An object (hash) of rules indexed by selector
13946 refreshCache : function(){
13947 return this.getRules(true);
13951 cacheStyleSheet : function(stylesheet){
13955 try{// try catch for cross domain access issue
13956 var ssRules = stylesheet.cssRules || stylesheet.rules;
13957 for(var j = ssRules.length-1; j >= 0; --j){
13958 rules[ssRules[j].selectorText] = ssRules[j];
13964 * Gets all css rules for the document
13965 * @param {Boolean} refreshCache true to refresh the internal cache
13966 * @return {Object} An object (hash) of rules indexed by selector
13968 getRules : function(refreshCache){
13969 if(rules == null || refreshCache){
13971 var ds = doc.styleSheets;
13972 for(var i =0, len = ds.length; i < len; i++){
13974 this.cacheStyleSheet(ds[i]);
13982 * Gets an an individual CSS rule by selector(s)
13983 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13984 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13985 * @return {CSSRule} The CSS rule or null if one is not found
13987 getRule : function(selector, refreshCache){
13988 var rs = this.getRules(refreshCache);
13989 if(!(selector instanceof Array)){
13990 return rs[selector];
13992 for(var i = 0; i < selector.length; i++){
13993 if(rs[selector[i]]){
13994 return rs[selector[i]];
14002 * Updates a rule property
14003 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14004 * @param {String} property The css property
14005 * @param {String} value The new value for the property
14006 * @return {Boolean} true If a rule was found and updated
14008 updateRule : function(selector, property, value){
14009 if(!(selector instanceof Array)){
14010 var rule = this.getRule(selector);
14012 rule.style[property.replace(camelRe, camelFn)] = value;
14016 for(var i = 0; i < selector.length; i++){
14017 if(this.updateRule(selector[i], property, value)){
14027 * Ext JS Library 1.1.1
14028 * Copyright(c) 2006-2007, Ext JS, LLC.
14030 * Originally Released Under LGPL - original licence link has changed is not relivant.
14033 * <script type="text/javascript">
14039 * @class Roo.util.ClickRepeater
14040 * @extends Roo.util.Observable
14042 * A wrapper class which can be applied to any element. Fires a "click" event while the
14043 * mouse is pressed. The interval between firings may be specified in the config but
14044 * defaults to 10 milliseconds.
14046 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14048 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14049 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14050 * Similar to an autorepeat key delay.
14051 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14052 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14053 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14054 * "interval" and "delay" are ignored. "immediate" is honored.
14055 * @cfg {Boolean} preventDefault True to prevent the default click event
14056 * @cfg {Boolean} stopDefault True to stop the default click event
14059 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14060 * 2007-02-02 jvs Renamed to ClickRepeater
14061 * 2007-02-03 jvs Modifications for FF Mac and Safari
14064 * @param {String/HTMLElement/Element} el The element to listen on
14065 * @param {Object} config
14067 Roo.util.ClickRepeater = function(el, config)
14069 this.el = Roo.get(el);
14070 this.el.unselectable();
14072 Roo.apply(this, config);
14077 * Fires when the mouse button is depressed.
14078 * @param {Roo.util.ClickRepeater} this
14080 "mousedown" : true,
14083 * Fires on a specified interval during the time the element is pressed.
14084 * @param {Roo.util.ClickRepeater} this
14089 * Fires when the mouse key is released.
14090 * @param {Roo.util.ClickRepeater} this
14095 this.el.on("mousedown", this.handleMouseDown, this);
14096 if(this.preventDefault || this.stopDefault){
14097 this.el.on("click", function(e){
14098 if(this.preventDefault){
14099 e.preventDefault();
14101 if(this.stopDefault){
14107 // allow inline handler
14109 this.on("click", this.handler, this.scope || this);
14112 Roo.util.ClickRepeater.superclass.constructor.call(this);
14115 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14118 preventDefault : true,
14119 stopDefault : false,
14123 handleMouseDown : function(){
14124 clearTimeout(this.timer);
14126 if(this.pressClass){
14127 this.el.addClass(this.pressClass);
14129 this.mousedownTime = new Date();
14131 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14132 this.el.on("mouseout", this.handleMouseOut, this);
14134 this.fireEvent("mousedown", this);
14135 this.fireEvent("click", this);
14137 this.timer = this.click.defer(this.delay || this.interval, this);
14141 click : function(){
14142 this.fireEvent("click", this);
14143 this.timer = this.click.defer(this.getInterval(), this);
14147 getInterval: function(){
14148 if(!this.accelerate){
14149 return this.interval;
14151 var pressTime = this.mousedownTime.getElapsed();
14152 if(pressTime < 500){
14154 }else if(pressTime < 1700){
14156 }else if(pressTime < 2600){
14158 }else if(pressTime < 3500){
14160 }else if(pressTime < 4400){
14162 }else if(pressTime < 5300){
14164 }else if(pressTime < 6200){
14172 handleMouseOut : function(){
14173 clearTimeout(this.timer);
14174 if(this.pressClass){
14175 this.el.removeClass(this.pressClass);
14177 this.el.on("mouseover", this.handleMouseReturn, this);
14181 handleMouseReturn : function(){
14182 this.el.un("mouseover", this.handleMouseReturn);
14183 if(this.pressClass){
14184 this.el.addClass(this.pressClass);
14190 handleMouseUp : function(){
14191 clearTimeout(this.timer);
14192 this.el.un("mouseover", this.handleMouseReturn);
14193 this.el.un("mouseout", this.handleMouseOut);
14194 Roo.get(document).un("mouseup", this.handleMouseUp);
14195 this.el.removeClass(this.pressClass);
14196 this.fireEvent("mouseup", this);
14200 * Ext JS Library 1.1.1
14201 * Copyright(c) 2006-2007, Ext JS, LLC.
14203 * Originally Released Under LGPL - original licence link has changed is not relivant.
14206 * <script type="text/javascript">
14211 * @class Roo.KeyNav
14212 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14213 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14214 * way to implement custom navigation schemes for any UI component.</p>
14215 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14216 * pageUp, pageDown, del, home, end. Usage:</p>
14218 var nav = new Roo.KeyNav("my-element", {
14219 "left" : function(e){
14220 this.moveLeft(e.ctrlKey);
14222 "right" : function(e){
14223 this.moveRight(e.ctrlKey);
14225 "enter" : function(e){
14232 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14233 * @param {Object} config The config
14235 Roo.KeyNav = function(el, config){
14236 this.el = Roo.get(el);
14237 Roo.apply(this, config);
14238 if(!this.disabled){
14239 this.disabled = true;
14244 Roo.KeyNav.prototype = {
14246 * @cfg {Boolean} disabled
14247 * True to disable this KeyNav instance (defaults to false)
14251 * @cfg {String} defaultEventAction
14252 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14253 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14254 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14256 defaultEventAction: "stopEvent",
14258 * @cfg {Boolean} forceKeyDown
14259 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14260 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14261 * handle keydown instead of keypress.
14263 forceKeyDown : false,
14266 prepareEvent : function(e){
14267 var k = e.getKey();
14268 var h = this.keyToHandler[k];
14269 //if(h && this[h]){
14270 // e.stopPropagation();
14272 if(Roo.isSafari && h && k >= 37 && k <= 40){
14278 relay : function(e){
14279 var k = e.getKey();
14280 var h = this.keyToHandler[k];
14282 if(this.doRelay(e, this[h], h) !== true){
14283 e[this.defaultEventAction]();
14289 doRelay : function(e, h, hname){
14290 return h.call(this.scope || this, e);
14293 // possible handlers
14307 // quick lookup hash
14324 * Enable this KeyNav
14326 enable: function(){
14328 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14329 // the EventObject will normalize Safari automatically
14330 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14331 this.el.on("keydown", this.relay, this);
14333 this.el.on("keydown", this.prepareEvent, this);
14334 this.el.on("keypress", this.relay, this);
14336 this.disabled = false;
14341 * Disable this KeyNav
14343 disable: function(){
14344 if(!this.disabled){
14345 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14346 this.el.un("keydown", this.relay);
14348 this.el.un("keydown", this.prepareEvent);
14349 this.el.un("keypress", this.relay);
14351 this.disabled = true;
14356 * Ext JS Library 1.1.1
14357 * Copyright(c) 2006-2007, Ext JS, LLC.
14359 * Originally Released Under LGPL - original licence link has changed is not relivant.
14362 * <script type="text/javascript">
14367 * @class Roo.KeyMap
14368 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14369 * The constructor accepts the same config object as defined by {@link #addBinding}.
14370 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14371 * combination it will call the function with this signature (if the match is a multi-key
14372 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14373 * A KeyMap can also handle a string representation of keys.<br />
14376 // map one key by key code
14377 var map = new Roo.KeyMap("my-element", {
14378 key: 13, // or Roo.EventObject.ENTER
14383 // map multiple keys to one action by string
14384 var map = new Roo.KeyMap("my-element", {
14390 // map multiple keys to multiple actions by strings and array of codes
14391 var map = new Roo.KeyMap("my-element", [
14394 fn: function(){ alert("Return was pressed"); }
14397 fn: function(){ alert('a, b or c was pressed'); }
14402 fn: function(){ alert('Control + shift + tab was pressed.'); }
14406 * <b>Note: A KeyMap starts enabled</b>
14408 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14409 * @param {Object} config The config (see {@link #addBinding})
14410 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14412 Roo.KeyMap = function(el, config, eventName){
14413 this.el = Roo.get(el);
14414 this.eventName = eventName || "keydown";
14415 this.bindings = [];
14417 this.addBinding(config);
14422 Roo.KeyMap.prototype = {
14424 * True to stop the event from bubbling and prevent the default browser action if the
14425 * key was handled by the KeyMap (defaults to false)
14431 * Add a new binding to this KeyMap. The following config object properties are supported:
14433 Property Type Description
14434 ---------- --------------- ----------------------------------------------------------------------
14435 key String/Array A single keycode or an array of keycodes to handle
14436 shift Boolean True to handle key only when shift is pressed (defaults to false)
14437 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14438 alt Boolean True to handle key only when alt is pressed (defaults to false)
14439 fn Function The function to call when KeyMap finds the expected key combination
14440 scope Object The scope of the callback function
14446 var map = new Roo.KeyMap(document, {
14447 key: Roo.EventObject.ENTER,
14452 //Add a new binding to the existing KeyMap later
14460 * @param {Object/Array} config A single KeyMap config or an array of configs
14462 addBinding : function(config){
14463 if(config instanceof Array){
14464 for(var i = 0, len = config.length; i < len; i++){
14465 this.addBinding(config[i]);
14469 var keyCode = config.key,
14470 shift = config.shift,
14471 ctrl = config.ctrl,
14474 scope = config.scope;
14475 if(typeof keyCode == "string"){
14477 var keyString = keyCode.toUpperCase();
14478 for(var j = 0, len = keyString.length; j < len; j++){
14479 ks.push(keyString.charCodeAt(j));
14483 var keyArray = keyCode instanceof Array;
14484 var handler = function(e){
14485 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14486 var k = e.getKey();
14488 for(var i = 0, len = keyCode.length; i < len; i++){
14489 if(keyCode[i] == k){
14490 if(this.stopEvent){
14493 fn.call(scope || window, k, e);
14499 if(this.stopEvent){
14502 fn.call(scope || window, k, e);
14507 this.bindings.push(handler);
14511 * Shorthand for adding a single key listener
14512 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14513 * following options:
14514 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14515 * @param {Function} fn The function to call
14516 * @param {Object} scope (optional) The scope of the function
14518 on : function(key, fn, scope){
14519 var keyCode, shift, ctrl, alt;
14520 if(typeof key == "object" && !(key instanceof Array)){
14539 handleKeyDown : function(e){
14540 if(this.enabled){ //just in case
14541 var b = this.bindings;
14542 for(var i = 0, len = b.length; i < len; i++){
14543 b[i].call(this, e);
14549 * Returns true if this KeyMap is enabled
14550 * @return {Boolean}
14552 isEnabled : function(){
14553 return this.enabled;
14557 * Enables this KeyMap
14559 enable: function(){
14561 this.el.on(this.eventName, this.handleKeyDown, this);
14562 this.enabled = true;
14567 * Disable this KeyMap
14569 disable: function(){
14571 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14572 this.enabled = false;
14577 * Ext JS Library 1.1.1
14578 * Copyright(c) 2006-2007, Ext JS, LLC.
14580 * Originally Released Under LGPL - original licence link has changed is not relivant.
14583 * <script type="text/javascript">
14588 * @class Roo.util.TextMetrics
14589 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14590 * wide, in pixels, a given block of text will be.
14593 Roo.util.TextMetrics = function(){
14597 * Measures the size of the specified text
14598 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14599 * that can affect the size of the rendered text
14600 * @param {String} text The text to measure
14601 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14602 * in order to accurately measure the text height
14603 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14605 measure : function(el, text, fixedWidth){
14607 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14610 shared.setFixedWidth(fixedWidth || 'auto');
14611 return shared.getSize(text);
14615 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14616 * the overhead of multiple calls to initialize the style properties on each measurement.
14617 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14618 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14619 * in order to accurately measure the text height
14620 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14622 createInstance : function(el, fixedWidth){
14623 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14630 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14631 var ml = new Roo.Element(document.createElement('div'));
14632 document.body.appendChild(ml.dom);
14633 ml.position('absolute');
14634 ml.setLeftTop(-1000, -1000);
14638 ml.setWidth(fixedWidth);
14643 * Returns the size of the specified text based on the internal element's style and width properties
14644 * @memberOf Roo.util.TextMetrics.Instance#
14645 * @param {String} text The text to measure
14646 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14648 getSize : function(text){
14650 var s = ml.getSize();
14656 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14657 * that can affect the size of the rendered text
14658 * @memberOf Roo.util.TextMetrics.Instance#
14659 * @param {String/HTMLElement} el The element, dom node or id
14661 bind : function(el){
14663 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14668 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14669 * to set a fixed width in order to accurately measure the text height.
14670 * @memberOf Roo.util.TextMetrics.Instance#
14671 * @param {Number} width The width to set on the element
14673 setFixedWidth : function(width){
14674 ml.setWidth(width);
14678 * Returns the measured width of the specified text
14679 * @memberOf Roo.util.TextMetrics.Instance#
14680 * @param {String} text The text to measure
14681 * @return {Number} width The width in pixels
14683 getWidth : function(text){
14684 ml.dom.style.width = 'auto';
14685 return this.getSize(text).width;
14689 * Returns the measured height of the specified text. For multiline text, be sure to call
14690 * {@link #setFixedWidth} if necessary.
14691 * @memberOf Roo.util.TextMetrics.Instance#
14692 * @param {String} text The text to measure
14693 * @return {Number} height The height in pixels
14695 getHeight : function(text){
14696 return this.getSize(text).height;
14700 instance.bind(bindTo);
14705 // backwards compat
14706 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14708 * Ext JS Library 1.1.1
14709 * Copyright(c) 2006-2007, Ext JS, LLC.
14711 * Originally Released Under LGPL - original licence link has changed is not relivant.
14714 * <script type="text/javascript">
14718 * @class Roo.state.Provider
14719 * Abstract base class for state provider implementations. This class provides methods
14720 * for encoding and decoding <b>typed</b> variables including dates and defines the
14721 * Provider interface.
14723 Roo.state.Provider = function(){
14725 * @event statechange
14726 * Fires when a state change occurs.
14727 * @param {Provider} this This state provider
14728 * @param {String} key The state key which was changed
14729 * @param {String} value The encoded value for the state
14732 "statechange": true
14735 Roo.state.Provider.superclass.constructor.call(this);
14737 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14739 * Returns the current value for a key
14740 * @param {String} name The key name
14741 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14742 * @return {Mixed} The state data
14744 get : function(name, defaultValue){
14745 return typeof this.state[name] == "undefined" ?
14746 defaultValue : this.state[name];
14750 * Clears a value from the state
14751 * @param {String} name The key name
14753 clear : function(name){
14754 delete this.state[name];
14755 this.fireEvent("statechange", this, name, null);
14759 * Sets the value for a key
14760 * @param {String} name The key name
14761 * @param {Mixed} value The value to set
14763 set : function(name, value){
14764 this.state[name] = value;
14765 this.fireEvent("statechange", this, name, value);
14769 * Decodes a string previously encoded with {@link #encodeValue}.
14770 * @param {String} value The value to decode
14771 * @return {Mixed} The decoded value
14773 decodeValue : function(cookie){
14774 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14775 var matches = re.exec(unescape(cookie));
14776 if(!matches || !matches[1]) return; // non state cookie
14777 var type = matches[1];
14778 var v = matches[2];
14781 return parseFloat(v);
14783 return new Date(Date.parse(v));
14788 var values = v.split("^");
14789 for(var i = 0, len = values.length; i < len; i++){
14790 all.push(this.decodeValue(values[i]));
14795 var values = v.split("^");
14796 for(var i = 0, len = values.length; i < len; i++){
14797 var kv = values[i].split("=");
14798 all[kv[0]] = this.decodeValue(kv[1]);
14807 * Encodes a value including type information. Decode with {@link #decodeValue}.
14808 * @param {Mixed} value The value to encode
14809 * @return {String} The encoded value
14811 encodeValue : function(v){
14813 if(typeof v == "number"){
14815 }else if(typeof v == "boolean"){
14816 enc = "b:" + (v ? "1" : "0");
14817 }else if(v instanceof Date){
14818 enc = "d:" + v.toGMTString();
14819 }else if(v instanceof Array){
14821 for(var i = 0, len = v.length; i < len; i++){
14822 flat += this.encodeValue(v[i]);
14823 if(i != len-1) flat += "^";
14826 }else if(typeof v == "object"){
14829 if(typeof v[key] != "function"){
14830 flat += key + "=" + this.encodeValue(v[key]) + "^";
14833 enc = "o:" + flat.substring(0, flat.length-1);
14837 return escape(enc);
14843 * Ext JS Library 1.1.1
14844 * Copyright(c) 2006-2007, Ext JS, LLC.
14846 * Originally Released Under LGPL - original licence link has changed is not relivant.
14849 * <script type="text/javascript">
14852 * @class Roo.state.Manager
14853 * This is the global state manager. By default all components that are "state aware" check this class
14854 * for state information if you don't pass them a custom state provider. In order for this class
14855 * to be useful, it must be initialized with a provider when your application initializes.
14857 // in your initialization function
14859 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14861 // supposed you have a {@link Roo.BorderLayout}
14862 var layout = new Roo.BorderLayout(...);
14863 layout.restoreState();
14864 // or a {Roo.BasicDialog}
14865 var dialog = new Roo.BasicDialog(...);
14866 dialog.restoreState();
14870 Roo.state.Manager = function(){
14871 var provider = new Roo.state.Provider();
14875 * Configures the default state provider for your application
14876 * @param {Provider} stateProvider The state provider to set
14878 setProvider : function(stateProvider){
14879 provider = stateProvider;
14883 * Returns the current value for a key
14884 * @param {String} name The key name
14885 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14886 * @return {Mixed} The state data
14888 get : function(key, defaultValue){
14889 return provider.get(key, defaultValue);
14893 * Sets the value for a key
14894 * @param {String} name The key name
14895 * @param {Mixed} value The state data
14897 set : function(key, value){
14898 provider.set(key, value);
14902 * Clears a value from the state
14903 * @param {String} name The key name
14905 clear : function(key){
14906 provider.clear(key);
14910 * Gets the currently configured state provider
14911 * @return {Provider} The state provider
14913 getProvider : function(){
14920 * Ext JS Library 1.1.1
14921 * Copyright(c) 2006-2007, Ext JS, LLC.
14923 * Originally Released Under LGPL - original licence link has changed is not relivant.
14926 * <script type="text/javascript">
14929 * @class Roo.state.CookieProvider
14930 * @extends Roo.state.Provider
14931 * The default Provider implementation which saves state via cookies.
14934 var cp = new Roo.state.CookieProvider({
14936 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14937 domain: "roojs.com"
14939 Roo.state.Manager.setProvider(cp);
14941 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14942 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14943 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14944 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14945 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14946 * domain the page is running on including the 'www' like 'www.roojs.com')
14947 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14949 * Create a new CookieProvider
14950 * @param {Object} config The configuration object
14952 Roo.state.CookieProvider = function(config){
14953 Roo.state.CookieProvider.superclass.constructor.call(this);
14955 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14956 this.domain = null;
14957 this.secure = false;
14958 Roo.apply(this, config);
14959 this.state = this.readCookies();
14962 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14964 set : function(name, value){
14965 if(typeof value == "undefined" || value === null){
14969 this.setCookie(name, value);
14970 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14974 clear : function(name){
14975 this.clearCookie(name);
14976 Roo.state.CookieProvider.superclass.clear.call(this, name);
14980 readCookies : function(){
14982 var c = document.cookie + ";";
14983 var re = /\s?(.*?)=(.*?);/g;
14985 while((matches = re.exec(c)) != null){
14986 var name = matches[1];
14987 var value = matches[2];
14988 if(name && name.substring(0,3) == "ys-"){
14989 cookies[name.substr(3)] = this.decodeValue(value);
14996 setCookie : function(name, value){
14997 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14998 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14999 ((this.path == null) ? "" : ("; path=" + this.path)) +
15000 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15001 ((this.secure == true) ? "; secure" : "");
15005 clearCookie : function(name){
15006 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15007 ((this.path == null) ? "" : ("; path=" + this.path)) +
15008 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15009 ((this.secure == true) ? "; secure" : "");
15013 * Ext JS Library 1.1.1
15014 * Copyright(c) 2006-2007, Ext JS, LLC.
15016 * Originally Released Under LGPL - original licence link has changed is not relivant.
15019 * <script type="text/javascript">
15024 * @class Roo.ComponentMgr
15025 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15028 Roo.ComponentMgr = function(){
15029 var all = new Roo.util.MixedCollection();
15033 * Registers a component.
15034 * @param {Roo.Component} c The component
15036 register : function(c){
15041 * Unregisters a component.
15042 * @param {Roo.Component} c The component
15044 unregister : function(c){
15049 * Returns a component by id
15050 * @param {String} id The component id
15052 get : function(id){
15053 return all.get(id);
15057 * Registers a function that will be called when a specified component is added to ComponentMgr
15058 * @param {String} id The component id
15059 * @param {Funtction} fn The callback function
15060 * @param {Object} scope The scope of the callback
15062 onAvailable : function(id, fn, scope){
15063 all.on("add", function(index, o){
15065 fn.call(scope || o, o);
15066 all.un("add", fn, scope);
15073 * Ext JS Library 1.1.1
15074 * Copyright(c) 2006-2007, Ext JS, LLC.
15076 * Originally Released Under LGPL - original licence link has changed is not relivant.
15079 * <script type="text/javascript">
15083 * @class Roo.Component
15084 * @extends Roo.util.Observable
15085 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15086 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15087 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15088 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15089 * All visual components (widgets) that require rendering into a layout should subclass Component.
15091 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15092 * 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
15093 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15095 Roo.Component = function(config){
15096 config = config || {};
15097 if(config.tagName || config.dom || typeof config == "string"){ // element object
15098 config = {el: config, id: config.id || config};
15100 this.initialConfig = config;
15102 Roo.apply(this, config);
15106 * Fires after the component is disabled.
15107 * @param {Roo.Component} this
15112 * Fires after the component is enabled.
15113 * @param {Roo.Component} this
15117 * @event beforeshow
15118 * Fires before the component is shown. Return false to stop the show.
15119 * @param {Roo.Component} this
15124 * Fires after the component is shown.
15125 * @param {Roo.Component} this
15129 * @event beforehide
15130 * Fires before the component is hidden. Return false to stop the hide.
15131 * @param {Roo.Component} this
15136 * Fires after the component is hidden.
15137 * @param {Roo.Component} this
15141 * @event beforerender
15142 * Fires before the component is rendered. Return false to stop the render.
15143 * @param {Roo.Component} this
15145 beforerender : true,
15148 * Fires after the component is rendered.
15149 * @param {Roo.Component} this
15153 * @event beforedestroy
15154 * Fires before the component is destroyed. Return false to stop the destroy.
15155 * @param {Roo.Component} this
15157 beforedestroy : true,
15160 * Fires after the component is destroyed.
15161 * @param {Roo.Component} this
15166 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15168 Roo.ComponentMgr.register(this);
15169 Roo.Component.superclass.constructor.call(this);
15170 this.initComponent();
15171 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15172 this.render(this.renderTo);
15173 delete this.renderTo;
15178 Roo.Component.AUTO_ID = 1000;
15180 Roo.extend(Roo.Component, Roo.util.Observable, {
15182 * @scope Roo.Component.prototype
15184 * true if this component is hidden. Read-only.
15189 * true if this component is disabled. Read-only.
15194 * true if this component has been rendered. Read-only.
15198 /** @cfg {String} disableClass
15199 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15201 disabledClass : "x-item-disabled",
15202 /** @cfg {Boolean} allowDomMove
15203 * Whether the component can move the Dom node when rendering (defaults to true).
15205 allowDomMove : true,
15206 /** @cfg {String} hideMode
15207 * How this component should hidden. Supported values are
15208 * "visibility" (css visibility), "offsets" (negative offset position) and
15209 * "display" (css display) - defaults to "display".
15211 hideMode: 'display',
15214 ctype : "Roo.Component",
15217 * @cfg {String} actionMode
15218 * which property holds the element that used for hide() / show() / disable() / enable()
15224 getActionEl : function(){
15225 return this[this.actionMode];
15228 initComponent : Roo.emptyFn,
15230 * If this is a lazy rendering component, render it to its container element.
15231 * @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.
15233 render : function(container, position){
15234 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15235 if(!container && this.el){
15236 this.el = Roo.get(this.el);
15237 container = this.el.dom.parentNode;
15238 this.allowDomMove = false;
15240 this.container = Roo.get(container);
15241 this.rendered = true;
15242 if(position !== undefined){
15243 if(typeof position == 'number'){
15244 position = this.container.dom.childNodes[position];
15246 position = Roo.getDom(position);
15249 this.onRender(this.container, position || null);
15251 this.el.addClass(this.cls);
15255 this.el.applyStyles(this.style);
15258 this.fireEvent("render", this);
15259 this.afterRender(this.container);
15271 // default function is not really useful
15272 onRender : function(ct, position){
15274 this.el = Roo.get(this.el);
15275 if(this.allowDomMove !== false){
15276 ct.dom.insertBefore(this.el.dom, position);
15282 getAutoCreate : function(){
15283 var cfg = typeof this.autoCreate == "object" ?
15284 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15285 if(this.id && !cfg.id){
15292 afterRender : Roo.emptyFn,
15295 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15296 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15298 destroy : function(){
15299 if(this.fireEvent("beforedestroy", this) !== false){
15300 this.purgeListeners();
15301 this.beforeDestroy();
15303 this.el.removeAllListeners();
15305 if(this.actionMode == "container"){
15306 this.container.remove();
15310 Roo.ComponentMgr.unregister(this);
15311 this.fireEvent("destroy", this);
15316 beforeDestroy : function(){
15321 onDestroy : function(){
15326 * Returns the underlying {@link Roo.Element}.
15327 * @return {Roo.Element} The element
15329 getEl : function(){
15334 * Returns the id of this component.
15337 getId : function(){
15342 * Try to focus this component.
15343 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15344 * @return {Roo.Component} this
15346 focus : function(selectText){
15349 if(selectText === true){
15350 this.el.dom.select();
15365 * Disable this component.
15366 * @return {Roo.Component} this
15368 disable : function(){
15372 this.disabled = true;
15373 this.fireEvent("disable", this);
15378 onDisable : function(){
15379 this.getActionEl().addClass(this.disabledClass);
15380 this.el.dom.disabled = true;
15384 * Enable this component.
15385 * @return {Roo.Component} this
15387 enable : function(){
15391 this.disabled = false;
15392 this.fireEvent("enable", this);
15397 onEnable : function(){
15398 this.getActionEl().removeClass(this.disabledClass);
15399 this.el.dom.disabled = false;
15403 * Convenience function for setting disabled/enabled by boolean.
15404 * @param {Boolean} disabled
15406 setDisabled : function(disabled){
15407 this[disabled ? "disable" : "enable"]();
15411 * Show this component.
15412 * @return {Roo.Component} this
15415 if(this.fireEvent("beforeshow", this) !== false){
15416 this.hidden = false;
15420 this.fireEvent("show", this);
15426 onShow : function(){
15427 var ae = this.getActionEl();
15428 if(this.hideMode == 'visibility'){
15429 ae.dom.style.visibility = "visible";
15430 }else if(this.hideMode == 'offsets'){
15431 ae.removeClass('x-hidden');
15433 ae.dom.style.display = "";
15438 * Hide this component.
15439 * @return {Roo.Component} this
15442 if(this.fireEvent("beforehide", this) !== false){
15443 this.hidden = true;
15447 this.fireEvent("hide", this);
15453 onHide : function(){
15454 var ae = this.getActionEl();
15455 if(this.hideMode == 'visibility'){
15456 ae.dom.style.visibility = "hidden";
15457 }else if(this.hideMode == 'offsets'){
15458 ae.addClass('x-hidden');
15460 ae.dom.style.display = "none";
15465 * Convenience function to hide or show this component by boolean.
15466 * @param {Boolean} visible True to show, false to hide
15467 * @return {Roo.Component} this
15469 setVisible: function(visible){
15479 * Returns true if this component is visible.
15481 isVisible : function(){
15482 return this.getActionEl().isVisible();
15485 cloneConfig : function(overrides){
15486 overrides = overrides || {};
15487 var id = overrides.id || Roo.id();
15488 var cfg = Roo.applyIf(overrides, this.initialConfig);
15489 cfg.id = id; // prevent dup id
15490 return new this.constructor(cfg);
15494 * Ext JS Library 1.1.1
15495 * Copyright(c) 2006-2007, Ext JS, LLC.
15497 * Originally Released Under LGPL - original licence link has changed is not relivant.
15500 * <script type="text/javascript">
15504 * @class Roo.BoxComponent
15505 * @extends Roo.Component
15506 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15507 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15508 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15509 * layout containers.
15511 * @param {Roo.Element/String/Object} config The configuration options.
15513 Roo.BoxComponent = function(config){
15514 Roo.Component.call(this, config);
15518 * Fires after the component is resized.
15519 * @param {Roo.Component} this
15520 * @param {Number} adjWidth The box-adjusted width that was set
15521 * @param {Number} adjHeight The box-adjusted height that was set
15522 * @param {Number} rawWidth The width that was originally specified
15523 * @param {Number} rawHeight The height that was originally specified
15528 * Fires after the component is moved.
15529 * @param {Roo.Component} this
15530 * @param {Number} x The new x position
15531 * @param {Number} y The new y position
15537 Roo.extend(Roo.BoxComponent, Roo.Component, {
15538 // private, set in afterRender to signify that the component has been rendered
15540 // private, used to defer height settings to subclasses
15541 deferHeight: false,
15542 /** @cfg {Number} width
15543 * width (optional) size of component
15545 /** @cfg {Number} height
15546 * height (optional) size of component
15550 * Sets the width and height of the component. This method fires the resize event. This method can accept
15551 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15552 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15553 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15554 * @return {Roo.BoxComponent} this
15556 setSize : function(w, h){
15557 // support for standard size objects
15558 if(typeof w == 'object'){
15563 if(!this.boxReady){
15569 // prevent recalcs when not needed
15570 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15573 this.lastSize = {width: w, height: h};
15575 var adj = this.adjustSize(w, h);
15576 var aw = adj.width, ah = adj.height;
15577 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15578 var rz = this.getResizeEl();
15579 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15580 rz.setSize(aw, ah);
15581 }else if(!this.deferHeight && ah !== undefined){
15583 }else if(aw !== undefined){
15586 this.onResize(aw, ah, w, h);
15587 this.fireEvent('resize', this, aw, ah, w, h);
15593 * Gets the current size of the component's underlying element.
15594 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15596 getSize : function(){
15597 return this.el.getSize();
15601 * Gets the current XY position of the component's underlying element.
15602 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15603 * @return {Array} The XY position of the element (e.g., [100, 200])
15605 getPosition : function(local){
15606 if(local === true){
15607 return [this.el.getLeft(true), this.el.getTop(true)];
15609 return this.xy || this.el.getXY();
15613 * Gets the current box measurements of the component's underlying element.
15614 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15615 * @returns {Object} box An object in the format {x, y, width, height}
15617 getBox : function(local){
15618 var s = this.el.getSize();
15620 s.x = this.el.getLeft(true);
15621 s.y = this.el.getTop(true);
15623 var xy = this.xy || this.el.getXY();
15631 * Sets the current box measurements of the component's underlying element.
15632 * @param {Object} box An object in the format {x, y, width, height}
15633 * @returns {Roo.BoxComponent} this
15635 updateBox : function(box){
15636 this.setSize(box.width, box.height);
15637 this.setPagePosition(box.x, box.y);
15642 getResizeEl : function(){
15643 return this.resizeEl || this.el;
15647 getPositionEl : function(){
15648 return this.positionEl || this.el;
15652 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15653 * This method fires the move event.
15654 * @param {Number} left The new left
15655 * @param {Number} top The new top
15656 * @returns {Roo.BoxComponent} this
15658 setPosition : function(x, y){
15661 if(!this.boxReady){
15664 var adj = this.adjustPosition(x, y);
15665 var ax = adj.x, ay = adj.y;
15667 var el = this.getPositionEl();
15668 if(ax !== undefined || ay !== undefined){
15669 if(ax !== undefined && ay !== undefined){
15670 el.setLeftTop(ax, ay);
15671 }else if(ax !== undefined){
15673 }else if(ay !== undefined){
15676 this.onPosition(ax, ay);
15677 this.fireEvent('move', this, ax, ay);
15683 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15684 * This method fires the move event.
15685 * @param {Number} x The new x position
15686 * @param {Number} y The new y position
15687 * @returns {Roo.BoxComponent} this
15689 setPagePosition : function(x, y){
15692 if(!this.boxReady){
15695 if(x === undefined || y === undefined){ // cannot translate undefined points
15698 var p = this.el.translatePoints(x, y);
15699 this.setPosition(p.left, p.top);
15704 onRender : function(ct, position){
15705 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15707 this.resizeEl = Roo.get(this.resizeEl);
15709 if(this.positionEl){
15710 this.positionEl = Roo.get(this.positionEl);
15715 afterRender : function(){
15716 Roo.BoxComponent.superclass.afterRender.call(this);
15717 this.boxReady = true;
15718 this.setSize(this.width, this.height);
15719 if(this.x || this.y){
15720 this.setPosition(this.x, this.y);
15722 if(this.pageX || this.pageY){
15723 this.setPagePosition(this.pageX, this.pageY);
15728 * Force the component's size to recalculate based on the underlying element's current height and width.
15729 * @returns {Roo.BoxComponent} this
15731 syncSize : function(){
15732 delete this.lastSize;
15733 this.setSize(this.el.getWidth(), this.el.getHeight());
15738 * Called after the component is resized, this method is empty by default but can be implemented by any
15739 * subclass that needs to perform custom logic after a resize occurs.
15740 * @param {Number} adjWidth The box-adjusted width that was set
15741 * @param {Number} adjHeight The box-adjusted height that was set
15742 * @param {Number} rawWidth The width that was originally specified
15743 * @param {Number} rawHeight The height that was originally specified
15745 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15750 * Called after the component is moved, this method is empty by default but can be implemented by any
15751 * subclass that needs to perform custom logic after a move occurs.
15752 * @param {Number} x The new x position
15753 * @param {Number} y The new y position
15755 onPosition : function(x, y){
15760 adjustSize : function(w, h){
15761 if(this.autoWidth){
15764 if(this.autoHeight){
15767 return {width : w, height: h};
15771 adjustPosition : function(x, y){
15772 return {x : x, y: y};
15775 * Original code for Roojs - LGPL
15776 * <script type="text/javascript">
15780 * @class Roo.XComponent
15781 * A delayed Element creator...
15782 * Or a way to group chunks of interface together.
15783 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15784 * used in conjunction with XComponent.build() it will create an instance of each element,
15785 * then call addxtype() to build the User interface.
15787 * Mypart.xyx = new Roo.XComponent({
15789 parent : 'Mypart.xyz', // empty == document.element.!!
15793 disabled : function() {}
15795 tree : function() { // return an tree of xtype declared components
15799 xtype : 'NestedLayoutPanel',
15806 * It can be used to build a big heiracy, with parent etc.
15807 * or you can just use this to render a single compoent to a dom element
15808 * MYPART.render(Roo.Element | String(id) | dom_element )
15815 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15816 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15818 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15820 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15821 * - if mulitple topModules exist, the last one is defined as the top module.
15825 * When the top level or multiple modules are to embedded into a existing HTML page,
15826 * the parent element can container '#id' of the element where the module will be drawn.
15830 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15831 * it relies more on a include mechanism, where sub modules are included into an outer page.
15832 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15834 * Bootstrap Roo Included elements
15836 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15837 * hence confusing the component builder as it thinks there are multiple top level elements.
15841 * @extends Roo.util.Observable
15843 * @param cfg {Object} configuration of component
15846 Roo.XComponent = function(cfg) {
15847 Roo.apply(this, cfg);
15851 * Fires when this the componnt is built
15852 * @param {Roo.XComponent} c the component
15857 this.region = this.region || 'center'; // default..
15858 Roo.XComponent.register(this);
15859 this.modules = false;
15860 this.el = false; // where the layout goes..
15864 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15867 * The created element (with Roo.factory())
15868 * @type {Roo.Layout}
15874 * for BC - use el in new code
15875 * @type {Roo.Layout}
15881 * for BC - use el in new code
15882 * @type {Roo.Layout}
15887 * @cfg {Function|boolean} disabled
15888 * If this module is disabled by some rule, return true from the funtion
15893 * @cfg {String} parent
15894 * Name of parent element which it get xtype added to..
15899 * @cfg {String} order
15900 * Used to set the order in which elements are created (usefull for multiple tabs)
15905 * @cfg {String} name
15906 * String to display while loading.
15910 * @cfg {String} region
15911 * Region to render component to (defaults to center)
15916 * @cfg {Array} items
15917 * A single item array - the first element is the root of the tree..
15918 * It's done this way to stay compatible with the Xtype system...
15924 * The method that retuns the tree of parts that make up this compoennt
15931 * render element to dom or tree
15932 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15935 render : function(el)
15939 var hp = this.parent ? 1 : 0;
15942 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15943 // if parent is a '#.....' string, then let's use that..
15944 var ename = this.parent.substr(1);
15945 this.parent = false;
15948 case 'bootstrap-body' :
15949 if (typeof(Roo.bootstrap.Body) != 'undefined') {
15950 this.parent = { el : new Roo.bootstrap.Body() };
15951 Roo.log("setting el to doc body");
15954 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15958 this.parent = { el : true};
15961 el = Roo.get(ename);
15966 if (!el && !this.parent) {
15967 Roo.log("Warning - element can not be found :#" + ename );
15971 Roo.log("EL:");Roo.log(el);
15972 Roo.log("this.parent.el:");Roo.log(this.parent.el);
15974 var tree = this._tree ? this._tree() : this.tree();
15976 // altertive root elements ??? - we need a better way to indicate these.
15977 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15978 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15980 if (!this.parent && is_alt) {
15981 //el = Roo.get(document.body);
15982 this.parent = { el : true };
15987 if (!this.parent) {
15989 Roo.log("no parent - creating one");
15991 el = el ? Roo.get(el) : false;
15993 // it's a top level one..
15995 el : new Roo.BorderLayout(el || document.body, {
16001 tabPosition: 'top',
16002 //resizeTabs: true,
16003 alwaysShowTabs: el && hp? false : true,
16004 hideTabs: el || !hp ? true : false,
16011 if (!this.parent.el) {
16012 // probably an old style ctor, which has been disabled.
16016 // The 'tree' method is '_tree now'
16018 tree.region = tree.region || this.region;
16020 if (this.parent.el === true) {
16021 // bootstrap... - body..
16022 this.parent.el = Roo.factory(tree);
16025 this.el = this.parent.el.addxtype(tree);
16026 this.fireEvent('built', this);
16028 this.panel = this.el;
16029 this.layout = this.panel.layout;
16030 this.parentLayout = this.parent.layout || false;
16036 Roo.apply(Roo.XComponent, {
16038 * @property hideProgress
16039 * true to disable the building progress bar.. usefull on single page renders.
16042 hideProgress : false,
16044 * @property buildCompleted
16045 * True when the builder has completed building the interface.
16048 buildCompleted : false,
16051 * @property topModule
16052 * the upper most module - uses document.element as it's constructor.
16059 * @property modules
16060 * array of modules to be created by registration system.
16061 * @type {Array} of Roo.XComponent
16066 * @property elmodules
16067 * array of modules to be created by which use #ID
16068 * @type {Array} of Roo.XComponent
16074 * @property build_from_html
16075 * Build elements from html - used by bootstrap HTML stuff
16076 * - this is cleared after build is completed
16077 * @type {boolean} true (default false)
16080 build_from_html : false,
16083 * Register components to be built later.
16085 * This solves the following issues
16086 * - Building is not done on page load, but after an authentication process has occured.
16087 * - Interface elements are registered on page load
16088 * - Parent Interface elements may not be loaded before child, so this handles that..
16095 module : 'Pman.Tab.projectMgr',
16097 parent : 'Pman.layout',
16098 disabled : false, // or use a function..
16101 * * @param {Object} details about module
16103 register : function(obj) {
16105 Roo.XComponent.event.fireEvent('register', obj);
16106 switch(typeof(obj.disabled) ) {
16112 if ( obj.disabled() ) {
16118 if (obj.disabled) {
16124 this.modules.push(obj);
16128 * convert a string to an object..
16129 * eg. 'AAA.BBB' -> finds AAA.BBB
16133 toObject : function(str)
16135 if (!str || typeof(str) == 'object') {
16138 if (str.substring(0,1) == '#') {
16142 var ar = str.split('.');
16147 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16149 throw "Module not found : " + str;
16153 throw "Module not found : " + str;
16155 Roo.each(ar, function(e) {
16156 if (typeof(o[e]) == 'undefined') {
16157 throw "Module not found : " + str;
16168 * move modules into their correct place in the tree..
16171 preBuild : function ()
16174 Roo.each(this.modules , function (obj)
16176 Roo.XComponent.event.fireEvent('beforebuild', obj);
16178 var opar = obj.parent;
16180 obj.parent = this.toObject(opar);
16182 Roo.log("parent:toObject failed: " + e.toString());
16187 Roo.debug && Roo.log("GOT top level module");
16188 Roo.debug && Roo.log(obj);
16189 obj.modules = new Roo.util.MixedCollection(false,
16190 function(o) { return o.order + '' }
16192 this.topModule = obj;
16195 // parent is a string (usually a dom element name..)
16196 if (typeof(obj.parent) == 'string') {
16197 this.elmodules.push(obj);
16200 if (obj.parent.constructor != Roo.XComponent) {
16201 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16203 if (!obj.parent.modules) {
16204 obj.parent.modules = new Roo.util.MixedCollection(false,
16205 function(o) { return o.order + '' }
16208 if (obj.parent.disabled) {
16209 obj.disabled = true;
16211 obj.parent.modules.add(obj);
16216 * make a list of modules to build.
16217 * @return {Array} list of modules.
16220 buildOrder : function()
16223 var cmp = function(a,b) {
16224 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16226 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16227 throw "No top level modules to build";
16230 // make a flat list in order of modules to build.
16231 var mods = this.topModule ? [ this.topModule ] : [];
16234 // elmodules (is a list of DOM based modules )
16235 Roo.each(this.elmodules, function(e) {
16237 if (!this.topModule &&
16238 typeof(e.parent) == 'string' &&
16239 e.parent.substring(0,1) == '#' &&
16240 Roo.get(e.parent.substr(1))
16243 _this.topModule = e;
16249 // add modules to their parents..
16250 var addMod = function(m) {
16251 Roo.debug && Roo.log("build Order: add: " + m.name);
16254 if (m.modules && !m.disabled) {
16255 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16256 m.modules.keySort('ASC', cmp );
16257 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16259 m.modules.each(addMod);
16261 Roo.debug && Roo.log("build Order: no child modules");
16263 // not sure if this is used any more..
16265 m.finalize.name = m.name + " (clean up) ";
16266 mods.push(m.finalize);
16270 if (this.topModule && this.topModule.modules) {
16271 this.topModule.modules.keySort('ASC', cmp );
16272 this.topModule.modules.each(addMod);
16278 * Build the registered modules.
16279 * @param {Object} parent element.
16280 * @param {Function} optional method to call after module has been added.
16284 build : function(opts)
16287 if (typeof(opts) != 'undefined') {
16288 Roo.apply(this,opts);
16292 var mods = this.buildOrder();
16294 //this.allmods = mods;
16295 //Roo.debug && Roo.log(mods);
16297 if (!mods.length) { // should not happen
16298 throw "NO modules!!!";
16302 var msg = "Building Interface...";
16303 // flash it up as modal - so we store the mask!?
16304 if (!this.hideProgress && Roo.MessageBox) {
16305 Roo.MessageBox.show({ title: 'loading' });
16306 Roo.MessageBox.show({
16307 title: "Please wait...",
16316 var total = mods.length;
16319 var progressRun = function() {
16320 if (!mods.length) {
16321 Roo.debug && Roo.log('hide?');
16322 if (!this.hideProgress && Roo.MessageBox) {
16323 Roo.MessageBox.hide();
16325 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16327 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16333 var m = mods.shift();
16336 Roo.debug && Roo.log(m);
16337 // not sure if this is supported any more.. - modules that are are just function
16338 if (typeof(m) == 'function') {
16340 return progressRun.defer(10, _this);
16344 msg = "Building Interface " + (total - mods.length) +
16346 (m.name ? (' - ' + m.name) : '');
16347 Roo.debug && Roo.log(msg);
16348 if (!this.hideProgress && Roo.MessageBox) {
16349 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16353 // is the module disabled?
16354 var disabled = (typeof(m.disabled) == 'function') ?
16355 m.disabled.call(m.module.disabled) : m.disabled;
16359 return progressRun(); // we do not update the display!
16367 // it's 10 on top level, and 1 on others??? why...
16368 return progressRun.defer(10, _this);
16371 progressRun.defer(1, _this);
16385 * wrapper for event.on - aliased later..
16386 * Typically use to register a event handler for register:
16388 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16397 Roo.XComponent.event = new Roo.util.Observable({
16401 * Fires when an Component is registered,
16402 * set the disable property on the Component to stop registration.
16403 * @param {Roo.XComponent} c the component being registerd.
16408 * @event beforebuild
16409 * Fires before each Component is built
16410 * can be used to apply permissions.
16411 * @param {Roo.XComponent} c the component being registerd.
16414 'beforebuild' : true,
16416 * @event buildcomplete
16417 * Fires on the top level element when all elements have been built
16418 * @param {Roo.XComponent} the top level component.
16420 'buildcomplete' : true
16425 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16428 * Ext JS Library 1.1.1
16429 * Copyright(c) 2006-2007, Ext JS, LLC.
16431 * Originally Released Under LGPL - original licence link has changed is not relivant.
16434 * <script type="text/javascript">
16440 * These classes are derivatives of the similarly named classes in the YUI Library.
16441 * The original license:
16442 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16443 * Code licensed under the BSD License:
16444 * http://developer.yahoo.net/yui/license.txt
16449 var Event=Roo.EventManager;
16450 var Dom=Roo.lib.Dom;
16453 * @class Roo.dd.DragDrop
16454 * @extends Roo.util.Observable
16455 * Defines the interface and base operation of items that that can be
16456 * dragged or can be drop targets. It was designed to be extended, overriding
16457 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16458 * Up to three html elements can be associated with a DragDrop instance:
16460 * <li>linked element: the element that is passed into the constructor.
16461 * This is the element which defines the boundaries for interaction with
16462 * other DragDrop objects.</li>
16463 * <li>handle element(s): The drag operation only occurs if the element that
16464 * was clicked matches a handle element. By default this is the linked
16465 * element, but there are times that you will want only a portion of the
16466 * linked element to initiate the drag operation, and the setHandleElId()
16467 * method provides a way to define this.</li>
16468 * <li>drag element: this represents the element that would be moved along
16469 * with the cursor during a drag operation. By default, this is the linked
16470 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16471 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16474 * This class should not be instantiated until the onload event to ensure that
16475 * the associated elements are available.
16476 * The following would define a DragDrop obj that would interact with any
16477 * other DragDrop obj in the "group1" group:
16479 * dd = new Roo.dd.DragDrop("div1", "group1");
16481 * Since none of the event handlers have been implemented, nothing would
16482 * actually happen if you were to run the code above. Normally you would
16483 * override this class or one of the default implementations, but you can
16484 * also override the methods you want on an instance of the class...
16486 * dd.onDragDrop = function(e, id) {
16487 * alert("dd was dropped on " + id);
16491 * @param {String} id of the element that is linked to this instance
16492 * @param {String} sGroup the group of related DragDrop objects
16493 * @param {object} config an object containing configurable attributes
16494 * Valid properties for DragDrop:
16495 * padding, isTarget, maintainOffset, primaryButtonOnly
16497 Roo.dd.DragDrop = function(id, sGroup, config) {
16499 this.init(id, sGroup, config);
16504 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16507 * The id of the element associated with this object. This is what we
16508 * refer to as the "linked element" because the size and position of
16509 * this element is used to determine when the drag and drop objects have
16517 * Configuration attributes passed into the constructor
16524 * The id of the element that will be dragged. By default this is same
16525 * as the linked element , but could be changed to another element. Ex:
16527 * @property dragElId
16534 * the id of the element that initiates the drag operation. By default
16535 * this is the linked element, but could be changed to be a child of this
16536 * element. This lets us do things like only starting the drag when the
16537 * header element within the linked html element is clicked.
16538 * @property handleElId
16545 * An associative array of HTML tags that will be ignored if clicked.
16546 * @property invalidHandleTypes
16547 * @type {string: string}
16549 invalidHandleTypes: null,
16552 * An associative array of ids for elements that will be ignored if clicked
16553 * @property invalidHandleIds
16554 * @type {string: string}
16556 invalidHandleIds: null,
16559 * An indexted array of css class names for elements that will be ignored
16561 * @property invalidHandleClasses
16564 invalidHandleClasses: null,
16567 * The linked element's absolute X position at the time the drag was
16569 * @property startPageX
16576 * The linked element's absolute X position at the time the drag was
16578 * @property startPageY
16585 * The group defines a logical collection of DragDrop objects that are
16586 * related. Instances only get events when interacting with other
16587 * DragDrop object in the same group. This lets us define multiple
16588 * groups using a single DragDrop subclass if we want.
16590 * @type {string: string}
16595 * Individual drag/drop instances can be locked. This will prevent
16596 * onmousedown start drag.
16604 * Lock this instance
16607 lock: function() { this.locked = true; },
16610 * Unlock this instace
16613 unlock: function() { this.locked = false; },
16616 * By default, all insances can be a drop target. This can be disabled by
16617 * setting isTarget to false.
16624 * The padding configured for this drag and drop object for calculating
16625 * the drop zone intersection with this object.
16632 * Cached reference to the linked element
16633 * @property _domRef
16639 * Internal typeof flag
16640 * @property __ygDragDrop
16643 __ygDragDrop: true,
16646 * Set to true when horizontal contraints are applied
16647 * @property constrainX
16654 * Set to true when vertical contraints are applied
16655 * @property constrainY
16662 * The left constraint
16670 * The right constraint
16678 * The up constraint
16687 * The down constraint
16695 * Maintain offsets when we resetconstraints. Set to true when you want
16696 * the position of the element relative to its parent to stay the same
16697 * when the page changes
16699 * @property maintainOffset
16702 maintainOffset: false,
16705 * Array of pixel locations the element will snap to if we specified a
16706 * horizontal graduation/interval. This array is generated automatically
16707 * when you define a tick interval.
16714 * Array of pixel locations the element will snap to if we specified a
16715 * vertical graduation/interval. This array is generated automatically
16716 * when you define a tick interval.
16723 * By default the drag and drop instance will only respond to the primary
16724 * button click (left button for a right-handed mouse). Set to true to
16725 * allow drag and drop to start with any mouse click that is propogated
16727 * @property primaryButtonOnly
16730 primaryButtonOnly: true,
16733 * The availabe property is false until the linked dom element is accessible.
16734 * @property available
16740 * By default, drags can only be initiated if the mousedown occurs in the
16741 * region the linked element is. This is done in part to work around a
16742 * bug in some browsers that mis-report the mousedown if the previous
16743 * mouseup happened outside of the window. This property is set to true
16744 * if outer handles are defined.
16746 * @property hasOuterHandles
16750 hasOuterHandles: false,
16753 * Code that executes immediately before the startDrag event
16754 * @method b4StartDrag
16757 b4StartDrag: function(x, y) { },
16760 * Abstract method called after a drag/drop object is clicked
16761 * and the drag or mousedown time thresholds have beeen met.
16762 * @method startDrag
16763 * @param {int} X click location
16764 * @param {int} Y click location
16766 startDrag: function(x, y) { /* override this */ },
16769 * Code that executes immediately before the onDrag event
16773 b4Drag: function(e) { },
16776 * Abstract method called during the onMouseMove event while dragging an
16779 * @param {Event} e the mousemove event
16781 onDrag: function(e) { /* override this */ },
16784 * Abstract method called when this element fist begins hovering over
16785 * another DragDrop obj
16786 * @method onDragEnter
16787 * @param {Event} e the mousemove event
16788 * @param {String|DragDrop[]} id In POINT mode, the element
16789 * id this is hovering over. In INTERSECT mode, an array of one or more
16790 * dragdrop items being hovered over.
16792 onDragEnter: function(e, id) { /* override this */ },
16795 * Code that executes immediately before the onDragOver event
16796 * @method b4DragOver
16799 b4DragOver: function(e) { },
16802 * Abstract method called when this element is hovering over another
16804 * @method onDragOver
16805 * @param {Event} e the mousemove event
16806 * @param {String|DragDrop[]} id In POINT mode, the element
16807 * id this is hovering over. In INTERSECT mode, an array of dd items
16808 * being hovered over.
16810 onDragOver: function(e, id) { /* override this */ },
16813 * Code that executes immediately before the onDragOut event
16814 * @method b4DragOut
16817 b4DragOut: function(e) { },
16820 * Abstract method called when we are no longer hovering over an element
16821 * @method onDragOut
16822 * @param {Event} e the mousemove event
16823 * @param {String|DragDrop[]} id In POINT mode, the element
16824 * id this was hovering over. In INTERSECT mode, an array of dd items
16825 * that the mouse is no longer over.
16827 onDragOut: function(e, id) { /* override this */ },
16830 * Code that executes immediately before the onDragDrop event
16831 * @method b4DragDrop
16834 b4DragDrop: function(e) { },
16837 * Abstract method called when this item is dropped on another DragDrop
16839 * @method onDragDrop
16840 * @param {Event} e the mouseup event
16841 * @param {String|DragDrop[]} id In POINT mode, the element
16842 * id this was dropped on. In INTERSECT mode, an array of dd items this
16845 onDragDrop: function(e, id) { /* override this */ },
16848 * Abstract method called when this item is dropped on an area with no
16850 * @method onInvalidDrop
16851 * @param {Event} e the mouseup event
16853 onInvalidDrop: function(e) { /* override this */ },
16856 * Code that executes immediately before the endDrag event
16857 * @method b4EndDrag
16860 b4EndDrag: function(e) { },
16863 * Fired when we are done dragging the object
16865 * @param {Event} e the mouseup event
16867 endDrag: function(e) { /* override this */ },
16870 * Code executed immediately before the onMouseDown event
16871 * @method b4MouseDown
16872 * @param {Event} e the mousedown event
16875 b4MouseDown: function(e) { },
16878 * Event handler that fires when a drag/drop obj gets a mousedown
16879 * @method onMouseDown
16880 * @param {Event} e the mousedown event
16882 onMouseDown: function(e) { /* override this */ },
16885 * Event handler that fires when a drag/drop obj gets a mouseup
16886 * @method onMouseUp
16887 * @param {Event} e the mouseup event
16889 onMouseUp: function(e) { /* override this */ },
16892 * Override the onAvailable method to do what is needed after the initial
16893 * position was determined.
16894 * @method onAvailable
16896 onAvailable: function () {
16900 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16903 defaultPadding : {left:0, right:0, top:0, bottom:0},
16906 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16910 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16911 { dragElId: "existingProxyDiv" });
16912 dd.startDrag = function(){
16913 this.constrainTo("parent-id");
16916 * Or you can initalize it using the {@link Roo.Element} object:
16918 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16919 startDrag : function(){
16920 this.constrainTo("parent-id");
16924 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16925 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16926 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16927 * an object containing the sides to pad. For example: {right:10, bottom:10}
16928 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16930 constrainTo : function(constrainTo, pad, inContent){
16931 if(typeof pad == "number"){
16932 pad = {left: pad, right:pad, top:pad, bottom:pad};
16934 pad = pad || this.defaultPadding;
16935 var b = Roo.get(this.getEl()).getBox();
16936 var ce = Roo.get(constrainTo);
16937 var s = ce.getScroll();
16938 var c, cd = ce.dom;
16939 if(cd == document.body){
16940 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16943 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16947 var topSpace = b.y - c.y;
16948 var leftSpace = b.x - c.x;
16950 this.resetConstraints();
16951 this.setXConstraint(leftSpace - (pad.left||0), // left
16952 c.width - leftSpace - b.width - (pad.right||0) //right
16954 this.setYConstraint(topSpace - (pad.top||0), //top
16955 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16960 * Returns a reference to the linked element
16962 * @return {HTMLElement} the html element
16964 getEl: function() {
16965 if (!this._domRef) {
16966 this._domRef = Roo.getDom(this.id);
16969 return this._domRef;
16973 * Returns a reference to the actual element to drag. By default this is
16974 * the same as the html element, but it can be assigned to another
16975 * element. An example of this can be found in Roo.dd.DDProxy
16976 * @method getDragEl
16977 * @return {HTMLElement} the html element
16979 getDragEl: function() {
16980 return Roo.getDom(this.dragElId);
16984 * Sets up the DragDrop object. Must be called in the constructor of any
16985 * Roo.dd.DragDrop subclass
16987 * @param id the id of the linked element
16988 * @param {String} sGroup the group of related items
16989 * @param {object} config configuration attributes
16991 init: function(id, sGroup, config) {
16992 this.initTarget(id, sGroup, config);
16993 if (!Roo.isTouch) {
16994 Event.on(this.id, "mousedown", this.handleMouseDown, this);
16996 Event.on(this.id, "touchstart", this.handleMouseDown, this);
16997 // Event.on(this.id, "selectstart", Event.preventDefault);
17001 * Initializes Targeting functionality only... the object does not
17002 * get a mousedown handler.
17003 * @method initTarget
17004 * @param id the id of the linked element
17005 * @param {String} sGroup the group of related items
17006 * @param {object} config configuration attributes
17008 initTarget: function(id, sGroup, config) {
17010 // configuration attributes
17011 this.config = config || {};
17013 // create a local reference to the drag and drop manager
17014 this.DDM = Roo.dd.DDM;
17015 // initialize the groups array
17018 // assume that we have an element reference instead of an id if the
17019 // parameter is not a string
17020 if (typeof id !== "string") {
17027 // add to an interaction group
17028 this.addToGroup((sGroup) ? sGroup : "default");
17030 // We don't want to register this as the handle with the manager
17031 // so we just set the id rather than calling the setter.
17032 this.handleElId = id;
17034 // the linked element is the element that gets dragged by default
17035 this.setDragElId(id);
17037 // by default, clicked anchors will not start drag operations.
17038 this.invalidHandleTypes = { A: "A" };
17039 this.invalidHandleIds = {};
17040 this.invalidHandleClasses = [];
17042 this.applyConfig();
17044 this.handleOnAvailable();
17048 * Applies the configuration parameters that were passed into the constructor.
17049 * This is supposed to happen at each level through the inheritance chain. So
17050 * a DDProxy implentation will execute apply config on DDProxy, DD, and
17051 * DragDrop in order to get all of the parameters that are available in
17053 * @method applyConfig
17055 applyConfig: function() {
17057 // configurable properties:
17058 // padding, isTarget, maintainOffset, primaryButtonOnly
17059 this.padding = this.config.padding || [0, 0, 0, 0];
17060 this.isTarget = (this.config.isTarget !== false);
17061 this.maintainOffset = (this.config.maintainOffset);
17062 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
17067 * Executed when the linked element is available
17068 * @method handleOnAvailable
17071 handleOnAvailable: function() {
17072 this.available = true;
17073 this.resetConstraints();
17074 this.onAvailable();
17078 * Configures the padding for the target zone in px. Effectively expands
17079 * (or reduces) the virtual object size for targeting calculations.
17080 * Supports css-style shorthand; if only one parameter is passed, all sides
17081 * will have that padding, and if only two are passed, the top and bottom
17082 * will have the first param, the left and right the second.
17083 * @method setPadding
17084 * @param {int} iTop Top pad
17085 * @param {int} iRight Right pad
17086 * @param {int} iBot Bot pad
17087 * @param {int} iLeft Left pad
17089 setPadding: function(iTop, iRight, iBot, iLeft) {
17090 // this.padding = [iLeft, iRight, iTop, iBot];
17091 if (!iRight && 0 !== iRight) {
17092 this.padding = [iTop, iTop, iTop, iTop];
17093 } else if (!iBot && 0 !== iBot) {
17094 this.padding = [iTop, iRight, iTop, iRight];
17096 this.padding = [iTop, iRight, iBot, iLeft];
17101 * Stores the initial placement of the linked element.
17102 * @method setInitialPosition
17103 * @param {int} diffX the X offset, default 0
17104 * @param {int} diffY the Y offset, default 0
17106 setInitPosition: function(diffX, diffY) {
17107 var el = this.getEl();
17109 if (!this.DDM.verifyEl(el)) {
17113 var dx = diffX || 0;
17114 var dy = diffY || 0;
17116 var p = Dom.getXY( el );
17118 this.initPageX = p[0] - dx;
17119 this.initPageY = p[1] - dy;
17121 this.lastPageX = p[0];
17122 this.lastPageY = p[1];
17125 this.setStartPosition(p);
17129 * Sets the start position of the element. This is set when the obj
17130 * is initialized, the reset when a drag is started.
17131 * @method setStartPosition
17132 * @param pos current position (from previous lookup)
17135 setStartPosition: function(pos) {
17136 var p = pos || Dom.getXY( this.getEl() );
17137 this.deltaSetXY = null;
17139 this.startPageX = p[0];
17140 this.startPageY = p[1];
17144 * Add this instance to a group of related drag/drop objects. All
17145 * instances belong to at least one group, and can belong to as many
17146 * groups as needed.
17147 * @method addToGroup
17148 * @param sGroup {string} the name of the group
17150 addToGroup: function(sGroup) {
17151 this.groups[sGroup] = true;
17152 this.DDM.regDragDrop(this, sGroup);
17156 * Remove's this instance from the supplied interaction group
17157 * @method removeFromGroup
17158 * @param {string} sGroup The group to drop
17160 removeFromGroup: function(sGroup) {
17161 if (this.groups[sGroup]) {
17162 delete this.groups[sGroup];
17165 this.DDM.removeDDFromGroup(this, sGroup);
17169 * Allows you to specify that an element other than the linked element
17170 * will be moved with the cursor during a drag
17171 * @method setDragElId
17172 * @param id {string} the id of the element that will be used to initiate the drag
17174 setDragElId: function(id) {
17175 this.dragElId = id;
17179 * Allows you to specify a child of the linked element that should be
17180 * used to initiate the drag operation. An example of this would be if
17181 * you have a content div with text and links. Clicking anywhere in the
17182 * content area would normally start the drag operation. Use this method
17183 * to specify that an element inside of the content div is the element
17184 * that starts the drag operation.
17185 * @method setHandleElId
17186 * @param id {string} the id of the element that will be used to
17187 * initiate the drag.
17189 setHandleElId: function(id) {
17190 if (typeof id !== "string") {
17193 this.handleElId = id;
17194 this.DDM.regHandle(this.id, id);
17198 * Allows you to set an element outside of the linked element as a drag
17200 * @method setOuterHandleElId
17201 * @param id the id of the element that will be used to initiate the drag
17203 setOuterHandleElId: function(id) {
17204 if (typeof id !== "string") {
17207 Event.on(id, "mousedown",
17208 this.handleMouseDown, this);
17209 this.setHandleElId(id);
17211 this.hasOuterHandles = true;
17215 * Remove all drag and drop hooks for this element
17218 unreg: function() {
17219 Event.un(this.id, "mousedown",
17220 this.handleMouseDown);
17221 Event.un(this.id, "touchstart",
17222 this.handleMouseDown);
17223 this._domRef = null;
17224 this.DDM._remove(this);
17227 destroy : function(){
17232 * Returns true if this instance is locked, or the drag drop mgr is locked
17233 * (meaning that all drag/drop is disabled on the page.)
17235 * @return {boolean} true if this obj or all drag/drop is locked, else
17238 isLocked: function() {
17239 return (this.DDM.isLocked() || this.locked);
17243 * Fired when this object is clicked
17244 * @method handleMouseDown
17246 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17249 handleMouseDown: function(e, oDD){
17251 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17252 //Roo.log('not touch/ button !=0');
17255 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17256 return; // double touch..
17260 if (this.isLocked()) {
17261 //Roo.log('locked');
17265 this.DDM.refreshCache(this.groups);
17266 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17267 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17268 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17269 //Roo.log('no outer handes or not over target');
17272 // Roo.log('check validator');
17273 if (this.clickValidator(e)) {
17274 // Roo.log('validate success');
17275 // set the initial element position
17276 this.setStartPosition();
17279 this.b4MouseDown(e);
17280 this.onMouseDown(e);
17282 this.DDM.handleMouseDown(e, this);
17284 this.DDM.stopEvent(e);
17292 clickValidator: function(e) {
17293 var target = e.getTarget();
17294 return ( this.isValidHandleChild(target) &&
17295 (this.id == this.handleElId ||
17296 this.DDM.handleWasClicked(target, this.id)) );
17300 * Allows you to specify a tag name that should not start a drag operation
17301 * when clicked. This is designed to facilitate embedding links within a
17302 * drag handle that do something other than start the drag.
17303 * @method addInvalidHandleType
17304 * @param {string} tagName the type of element to exclude
17306 addInvalidHandleType: function(tagName) {
17307 var type = tagName.toUpperCase();
17308 this.invalidHandleTypes[type] = type;
17312 * Lets you to specify an element id for a child of a drag handle
17313 * that should not initiate a drag
17314 * @method addInvalidHandleId
17315 * @param {string} id the element id of the element you wish to ignore
17317 addInvalidHandleId: function(id) {
17318 if (typeof id !== "string") {
17321 this.invalidHandleIds[id] = id;
17325 * Lets you specify a css class of elements that will not initiate a drag
17326 * @method addInvalidHandleClass
17327 * @param {string} cssClass the class of the elements you wish to ignore
17329 addInvalidHandleClass: function(cssClass) {
17330 this.invalidHandleClasses.push(cssClass);
17334 * Unsets an excluded tag name set by addInvalidHandleType
17335 * @method removeInvalidHandleType
17336 * @param {string} tagName the type of element to unexclude
17338 removeInvalidHandleType: function(tagName) {
17339 var type = tagName.toUpperCase();
17340 // this.invalidHandleTypes[type] = null;
17341 delete this.invalidHandleTypes[type];
17345 * Unsets an invalid handle id
17346 * @method removeInvalidHandleId
17347 * @param {string} id the id of the element to re-enable
17349 removeInvalidHandleId: function(id) {
17350 if (typeof id !== "string") {
17353 delete this.invalidHandleIds[id];
17357 * Unsets an invalid css class
17358 * @method removeInvalidHandleClass
17359 * @param {string} cssClass the class of the element(s) you wish to
17362 removeInvalidHandleClass: function(cssClass) {
17363 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17364 if (this.invalidHandleClasses[i] == cssClass) {
17365 delete this.invalidHandleClasses[i];
17371 * Checks the tag exclusion list to see if this click should be ignored
17372 * @method isValidHandleChild
17373 * @param {HTMLElement} node the HTMLElement to evaluate
17374 * @return {boolean} true if this is a valid tag type, false if not
17376 isValidHandleChild: function(node) {
17379 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17382 nodeName = node.nodeName.toUpperCase();
17384 nodeName = node.nodeName;
17386 valid = valid && !this.invalidHandleTypes[nodeName];
17387 valid = valid && !this.invalidHandleIds[node.id];
17389 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17390 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17399 * Create the array of horizontal tick marks if an interval was specified
17400 * in setXConstraint().
17401 * @method setXTicks
17404 setXTicks: function(iStartX, iTickSize) {
17406 this.xTickSize = iTickSize;
17410 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17412 this.xTicks[this.xTicks.length] = i;
17417 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17419 this.xTicks[this.xTicks.length] = i;
17424 this.xTicks.sort(this.DDM.numericSort) ;
17428 * Create the array of vertical tick marks if an interval was specified in
17429 * setYConstraint().
17430 * @method setYTicks
17433 setYTicks: function(iStartY, iTickSize) {
17435 this.yTickSize = iTickSize;
17439 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17441 this.yTicks[this.yTicks.length] = i;
17446 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17448 this.yTicks[this.yTicks.length] = i;
17453 this.yTicks.sort(this.DDM.numericSort) ;
17457 * By default, the element can be dragged any place on the screen. Use
17458 * this method to limit the horizontal travel of the element. Pass in
17459 * 0,0 for the parameters if you want to lock the drag to the y axis.
17460 * @method setXConstraint
17461 * @param {int} iLeft the number of pixels the element can move to the left
17462 * @param {int} iRight the number of pixels the element can move to the
17464 * @param {int} iTickSize optional parameter for specifying that the
17466 * should move iTickSize pixels at a time.
17468 setXConstraint: function(iLeft, iRight, iTickSize) {
17469 this.leftConstraint = iLeft;
17470 this.rightConstraint = iRight;
17472 this.minX = this.initPageX - iLeft;
17473 this.maxX = this.initPageX + iRight;
17474 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17476 this.constrainX = true;
17480 * Clears any constraints applied to this instance. Also clears ticks
17481 * since they can't exist independent of a constraint at this time.
17482 * @method clearConstraints
17484 clearConstraints: function() {
17485 this.constrainX = false;
17486 this.constrainY = false;
17491 * Clears any tick interval defined for this instance
17492 * @method clearTicks
17494 clearTicks: function() {
17495 this.xTicks = null;
17496 this.yTicks = null;
17497 this.xTickSize = 0;
17498 this.yTickSize = 0;
17502 * By default, the element can be dragged any place on the screen. Set
17503 * this to limit the vertical travel of the element. Pass in 0,0 for the
17504 * parameters if you want to lock the drag to the x axis.
17505 * @method setYConstraint
17506 * @param {int} iUp the number of pixels the element can move up
17507 * @param {int} iDown the number of pixels the element can move down
17508 * @param {int} iTickSize optional parameter for specifying that the
17509 * element should move iTickSize pixels at a time.
17511 setYConstraint: function(iUp, iDown, iTickSize) {
17512 this.topConstraint = iUp;
17513 this.bottomConstraint = iDown;
17515 this.minY = this.initPageY - iUp;
17516 this.maxY = this.initPageY + iDown;
17517 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17519 this.constrainY = true;
17524 * resetConstraints must be called if you manually reposition a dd element.
17525 * @method resetConstraints
17526 * @param {boolean} maintainOffset
17528 resetConstraints: function() {
17531 // Maintain offsets if necessary
17532 if (this.initPageX || this.initPageX === 0) {
17533 // figure out how much this thing has moved
17534 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17535 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17537 this.setInitPosition(dx, dy);
17539 // This is the first time we have detected the element's position
17541 this.setInitPosition();
17544 if (this.constrainX) {
17545 this.setXConstraint( this.leftConstraint,
17546 this.rightConstraint,
17550 if (this.constrainY) {
17551 this.setYConstraint( this.topConstraint,
17552 this.bottomConstraint,
17558 * Normally the drag element is moved pixel by pixel, but we can specify
17559 * that it move a number of pixels at a time. This method resolves the
17560 * location when we have it set up like this.
17562 * @param {int} val where we want to place the object
17563 * @param {int[]} tickArray sorted array of valid points
17564 * @return {int} the closest tick
17567 getTick: function(val, tickArray) {
17570 // If tick interval is not defined, it is effectively 1 pixel,
17571 // so we return the value passed to us.
17573 } else if (tickArray[0] >= val) {
17574 // The value is lower than the first tick, so we return the first
17576 return tickArray[0];
17578 for (var i=0, len=tickArray.length; i<len; ++i) {
17580 if (tickArray[next] && tickArray[next] >= val) {
17581 var diff1 = val - tickArray[i];
17582 var diff2 = tickArray[next] - val;
17583 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17587 // The value is larger than the last tick, so we return the last
17589 return tickArray[tickArray.length - 1];
17596 * @return {string} string representation of the dd obj
17598 toString: function() {
17599 return ("DragDrop " + this.id);
17607 * Ext JS Library 1.1.1
17608 * Copyright(c) 2006-2007, Ext JS, LLC.
17610 * Originally Released Under LGPL - original licence link has changed is not relivant.
17613 * <script type="text/javascript">
17618 * The drag and drop utility provides a framework for building drag and drop
17619 * applications. In addition to enabling drag and drop for specific elements,
17620 * the drag and drop elements are tracked by the manager class, and the
17621 * interactions between the various elements are tracked during the drag and
17622 * the implementing code is notified about these important moments.
17625 // Only load the library once. Rewriting the manager class would orphan
17626 // existing drag and drop instances.
17627 if (!Roo.dd.DragDropMgr) {
17630 * @class Roo.dd.DragDropMgr
17631 * DragDropMgr is a singleton that tracks the element interaction for
17632 * all DragDrop items in the window. Generally, you will not call
17633 * this class directly, but it does have helper methods that could
17634 * be useful in your DragDrop implementations.
17637 Roo.dd.DragDropMgr = function() {
17639 var Event = Roo.EventManager;
17644 * Two dimensional Array of registered DragDrop objects. The first
17645 * dimension is the DragDrop item group, the second the DragDrop
17648 * @type {string: string}
17655 * Array of element ids defined as drag handles. Used to determine
17656 * if the element that generated the mousedown event is actually the
17657 * handle and not the html element itself.
17658 * @property handleIds
17659 * @type {string: string}
17666 * the DragDrop object that is currently being dragged
17667 * @property dragCurrent
17675 * the DragDrop object(s) that are being hovered over
17676 * @property dragOvers
17684 * the X distance between the cursor and the object being dragged
17693 * the Y distance between the cursor and the object being dragged
17702 * Flag to determine if we should prevent the default behavior of the
17703 * events we define. By default this is true, but this can be set to
17704 * false if you need the default behavior (not recommended)
17705 * @property preventDefault
17709 preventDefault: true,
17712 * Flag to determine if we should stop the propagation of the events
17713 * we generate. This is true by default but you may want to set it to
17714 * false if the html element contains other features that require the
17716 * @property stopPropagation
17720 stopPropagation: true,
17723 * Internal flag that is set to true when drag and drop has been
17725 * @property initialized
17732 * All drag and drop can be disabled.
17740 * Called the first time an element is registered.
17746 this.initialized = true;
17750 * In point mode, drag and drop interaction is defined by the
17751 * location of the cursor during the drag/drop
17759 * In intersect mode, drag and drop interactio nis defined by the
17760 * overlap of two or more drag and drop objects.
17761 * @property INTERSECT
17768 * The current drag and drop mode. Default: POINT
17776 * Runs method on all drag and drop objects
17777 * @method _execOnAll
17781 _execOnAll: function(sMethod, args) {
17782 for (var i in this.ids) {
17783 for (var j in this.ids[i]) {
17784 var oDD = this.ids[i][j];
17785 if (! this.isTypeOfDD(oDD)) {
17788 oDD[sMethod].apply(oDD, args);
17794 * Drag and drop initialization. Sets up the global event handlers
17799 _onLoad: function() {
17803 if (!Roo.isTouch) {
17804 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17805 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17807 Event.on(document, "touchend", this.handleMouseUp, this, true);
17808 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17810 Event.on(window, "unload", this._onUnload, this, true);
17811 Event.on(window, "resize", this._onResize, this, true);
17812 // Event.on(window, "mouseout", this._test);
17817 * Reset constraints on all drag and drop objs
17818 * @method _onResize
17822 _onResize: function(e) {
17823 this._execOnAll("resetConstraints", []);
17827 * Lock all drag and drop functionality
17831 lock: function() { this.locked = true; },
17834 * Unlock all drag and drop functionality
17838 unlock: function() { this.locked = false; },
17841 * Is drag and drop locked?
17843 * @return {boolean} True if drag and drop is locked, false otherwise.
17846 isLocked: function() { return this.locked; },
17849 * Location cache that is set for all drag drop objects when a drag is
17850 * initiated, cleared when the drag is finished.
17851 * @property locationCache
17858 * Set useCache to false if you want to force object the lookup of each
17859 * drag and drop linked element constantly during a drag.
17860 * @property useCache
17867 * The number of pixels that the mouse needs to move after the
17868 * mousedown before the drag is initiated. Default=3;
17869 * @property clickPixelThresh
17873 clickPixelThresh: 3,
17876 * The number of milliseconds after the mousedown event to initiate the
17877 * drag if we don't get a mouseup event. Default=1000
17878 * @property clickTimeThresh
17882 clickTimeThresh: 350,
17885 * Flag that indicates that either the drag pixel threshold or the
17886 * mousdown time threshold has been met
17887 * @property dragThreshMet
17892 dragThreshMet: false,
17895 * Timeout used for the click time threshold
17896 * @property clickTimeout
17901 clickTimeout: null,
17904 * The X position of the mousedown event stored for later use when a
17905 * drag threshold is met.
17914 * The Y position of the mousedown event stored for later use when a
17915 * drag threshold is met.
17924 * Each DragDrop instance must be registered with the DragDropMgr.
17925 * This is executed in DragDrop.init()
17926 * @method regDragDrop
17927 * @param {DragDrop} oDD the DragDrop object to register
17928 * @param {String} sGroup the name of the group this element belongs to
17931 regDragDrop: function(oDD, sGroup) {
17932 if (!this.initialized) { this.init(); }
17934 if (!this.ids[sGroup]) {
17935 this.ids[sGroup] = {};
17937 this.ids[sGroup][oDD.id] = oDD;
17941 * Removes the supplied dd instance from the supplied group. Executed
17942 * by DragDrop.removeFromGroup, so don't call this function directly.
17943 * @method removeDDFromGroup
17947 removeDDFromGroup: function(oDD, sGroup) {
17948 if (!this.ids[sGroup]) {
17949 this.ids[sGroup] = {};
17952 var obj = this.ids[sGroup];
17953 if (obj && obj[oDD.id]) {
17954 delete obj[oDD.id];
17959 * Unregisters a drag and drop item. This is executed in
17960 * DragDrop.unreg, use that method instead of calling this directly.
17965 _remove: function(oDD) {
17966 for (var g in oDD.groups) {
17967 if (g && this.ids[g][oDD.id]) {
17968 delete this.ids[g][oDD.id];
17971 delete this.handleIds[oDD.id];
17975 * Each DragDrop handle element must be registered. This is done
17976 * automatically when executing DragDrop.setHandleElId()
17977 * @method regHandle
17978 * @param {String} sDDId the DragDrop id this element is a handle for
17979 * @param {String} sHandleId the id of the element that is the drag
17983 regHandle: function(sDDId, sHandleId) {
17984 if (!this.handleIds[sDDId]) {
17985 this.handleIds[sDDId] = {};
17987 this.handleIds[sDDId][sHandleId] = sHandleId;
17991 * Utility function to determine if a given element has been
17992 * registered as a drag drop item.
17993 * @method isDragDrop
17994 * @param {String} id the element id to check
17995 * @return {boolean} true if this element is a DragDrop item,
17999 isDragDrop: function(id) {
18000 return ( this.getDDById(id) ) ? true : false;
18004 * Returns the drag and drop instances that are in all groups the
18005 * passed in instance belongs to.
18006 * @method getRelated
18007 * @param {DragDrop} p_oDD the obj to get related data for
18008 * @param {boolean} bTargetsOnly if true, only return targetable objs
18009 * @return {DragDrop[]} the related instances
18012 getRelated: function(p_oDD, bTargetsOnly) {
18014 for (var i in p_oDD.groups) {
18015 for (j in this.ids[i]) {
18016 var dd = this.ids[i][j];
18017 if (! this.isTypeOfDD(dd)) {
18020 if (!bTargetsOnly || dd.isTarget) {
18021 oDDs[oDDs.length] = dd;
18030 * Returns true if the specified dd target is a legal target for
18031 * the specifice drag obj
18032 * @method isLegalTarget
18033 * @param {DragDrop} the drag obj
18034 * @param {DragDrop} the target
18035 * @return {boolean} true if the target is a legal target for the
18039 isLegalTarget: function (oDD, oTargetDD) {
18040 var targets = this.getRelated(oDD, true);
18041 for (var i=0, len=targets.length;i<len;++i) {
18042 if (targets[i].id == oTargetDD.id) {
18051 * My goal is to be able to transparently determine if an object is
18052 * typeof DragDrop, and the exact subclass of DragDrop. typeof
18053 * returns "object", oDD.constructor.toString() always returns
18054 * "DragDrop" and not the name of the subclass. So for now it just
18055 * evaluates a well-known variable in DragDrop.
18056 * @method isTypeOfDD
18057 * @param {Object} the object to evaluate
18058 * @return {boolean} true if typeof oDD = DragDrop
18061 isTypeOfDD: function (oDD) {
18062 return (oDD && oDD.__ygDragDrop);
18066 * Utility function to determine if a given element has been
18067 * registered as a drag drop handle for the given Drag Drop object.
18069 * @param {String} id the element id to check
18070 * @return {boolean} true if this element is a DragDrop handle, false
18074 isHandle: function(sDDId, sHandleId) {
18075 return ( this.handleIds[sDDId] &&
18076 this.handleIds[sDDId][sHandleId] );
18080 * Returns the DragDrop instance for a given id
18081 * @method getDDById
18082 * @param {String} id the id of the DragDrop object
18083 * @return {DragDrop} the drag drop object, null if it is not found
18086 getDDById: function(id) {
18087 for (var i in this.ids) {
18088 if (this.ids[i][id]) {
18089 return this.ids[i][id];
18096 * Fired after a registered DragDrop object gets the mousedown event.
18097 * Sets up the events required to track the object being dragged
18098 * @method handleMouseDown
18099 * @param {Event} e the event
18100 * @param oDD the DragDrop object being dragged
18104 handleMouseDown: function(e, oDD) {
18106 Roo.QuickTips.disable();
18108 this.currentTarget = e.getTarget();
18110 this.dragCurrent = oDD;
18112 var el = oDD.getEl();
18114 // track start position
18115 this.startX = e.getPageX();
18116 this.startY = e.getPageY();
18118 this.deltaX = this.startX - el.offsetLeft;
18119 this.deltaY = this.startY - el.offsetTop;
18121 this.dragThreshMet = false;
18123 this.clickTimeout = setTimeout(
18125 var DDM = Roo.dd.DDM;
18126 DDM.startDrag(DDM.startX, DDM.startY);
18128 this.clickTimeThresh );
18132 * Fired when either the drag pixel threshol or the mousedown hold
18133 * time threshold has been met.
18134 * @method startDrag
18135 * @param x {int} the X position of the original mousedown
18136 * @param y {int} the Y position of the original mousedown
18139 startDrag: function(x, y) {
18140 clearTimeout(this.clickTimeout);
18141 if (this.dragCurrent) {
18142 this.dragCurrent.b4StartDrag(x, y);
18143 this.dragCurrent.startDrag(x, y);
18145 this.dragThreshMet = true;
18149 * Internal function to handle the mouseup event. Will be invoked
18150 * from the context of the document.
18151 * @method handleMouseUp
18152 * @param {Event} e the event
18156 handleMouseUp: function(e) {
18159 Roo.QuickTips.enable();
18161 if (! this.dragCurrent) {
18165 clearTimeout(this.clickTimeout);
18167 if (this.dragThreshMet) {
18168 this.fireEvents(e, true);
18178 * Utility to stop event propagation and event default, if these
18179 * features are turned on.
18180 * @method stopEvent
18181 * @param {Event} e the event as returned by this.getEvent()
18184 stopEvent: function(e){
18185 if(this.stopPropagation) {
18186 e.stopPropagation();
18189 if (this.preventDefault) {
18190 e.preventDefault();
18195 * Internal function to clean up event handlers after the drag
18196 * operation is complete
18198 * @param {Event} e the event
18202 stopDrag: function(e) {
18203 // Fire the drag end event for the item that was dragged
18204 if (this.dragCurrent) {
18205 if (this.dragThreshMet) {
18206 this.dragCurrent.b4EndDrag(e);
18207 this.dragCurrent.endDrag(e);
18210 this.dragCurrent.onMouseUp(e);
18213 this.dragCurrent = null;
18214 this.dragOvers = {};
18218 * Internal function to handle the mousemove event. Will be invoked
18219 * from the context of the html element.
18221 * @TODO figure out what we can do about mouse events lost when the
18222 * user drags objects beyond the window boundary. Currently we can
18223 * detect this in internet explorer by verifying that the mouse is
18224 * down during the mousemove event. Firefox doesn't give us the
18225 * button state on the mousemove event.
18226 * @method handleMouseMove
18227 * @param {Event} e the event
18231 handleMouseMove: function(e) {
18232 if (! this.dragCurrent) {
18236 // var button = e.which || e.button;
18238 // check for IE mouseup outside of page boundary
18239 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18241 return this.handleMouseUp(e);
18244 if (!this.dragThreshMet) {
18245 var diffX = Math.abs(this.startX - e.getPageX());
18246 var diffY = Math.abs(this.startY - e.getPageY());
18247 if (diffX > this.clickPixelThresh ||
18248 diffY > this.clickPixelThresh) {
18249 this.startDrag(this.startX, this.startY);
18253 if (this.dragThreshMet) {
18254 this.dragCurrent.b4Drag(e);
18255 this.dragCurrent.onDrag(e);
18256 if(!this.dragCurrent.moveOnly){
18257 this.fireEvents(e, false);
18267 * Iterates over all of the DragDrop elements to find ones we are
18268 * hovering over or dropping on
18269 * @method fireEvents
18270 * @param {Event} e the event
18271 * @param {boolean} isDrop is this a drop op or a mouseover op?
18275 fireEvents: function(e, isDrop) {
18276 var dc = this.dragCurrent;
18278 // If the user did the mouse up outside of the window, we could
18279 // get here even though we have ended the drag.
18280 if (!dc || dc.isLocked()) {
18284 var pt = e.getPoint();
18286 // cache the previous dragOver array
18292 var enterEvts = [];
18294 // Check to see if the object(s) we were hovering over is no longer
18295 // being hovered over so we can fire the onDragOut event
18296 for (var i in this.dragOvers) {
18298 var ddo = this.dragOvers[i];
18300 if (! this.isTypeOfDD(ddo)) {
18304 if (! this.isOverTarget(pt, ddo, this.mode)) {
18305 outEvts.push( ddo );
18308 oldOvers[i] = true;
18309 delete this.dragOvers[i];
18312 for (var sGroup in dc.groups) {
18314 if ("string" != typeof sGroup) {
18318 for (i in this.ids[sGroup]) {
18319 var oDD = this.ids[sGroup][i];
18320 if (! this.isTypeOfDD(oDD)) {
18324 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18325 if (this.isOverTarget(pt, oDD, this.mode)) {
18326 // look for drop interactions
18328 dropEvts.push( oDD );
18329 // look for drag enter and drag over interactions
18332 // initial drag over: dragEnter fires
18333 if (!oldOvers[oDD.id]) {
18334 enterEvts.push( oDD );
18335 // subsequent drag overs: dragOver fires
18337 overEvts.push( oDD );
18340 this.dragOvers[oDD.id] = oDD;
18348 if (outEvts.length) {
18349 dc.b4DragOut(e, outEvts);
18350 dc.onDragOut(e, outEvts);
18353 if (enterEvts.length) {
18354 dc.onDragEnter(e, enterEvts);
18357 if (overEvts.length) {
18358 dc.b4DragOver(e, overEvts);
18359 dc.onDragOver(e, overEvts);
18362 if (dropEvts.length) {
18363 dc.b4DragDrop(e, dropEvts);
18364 dc.onDragDrop(e, dropEvts);
18368 // fire dragout events
18370 for (i=0, len=outEvts.length; i<len; ++i) {
18371 dc.b4DragOut(e, outEvts[i].id);
18372 dc.onDragOut(e, outEvts[i].id);
18375 // fire enter events
18376 for (i=0,len=enterEvts.length; i<len; ++i) {
18377 // dc.b4DragEnter(e, oDD.id);
18378 dc.onDragEnter(e, enterEvts[i].id);
18381 // fire over events
18382 for (i=0,len=overEvts.length; i<len; ++i) {
18383 dc.b4DragOver(e, overEvts[i].id);
18384 dc.onDragOver(e, overEvts[i].id);
18387 // fire drop events
18388 for (i=0, len=dropEvts.length; i<len; ++i) {
18389 dc.b4DragDrop(e, dropEvts[i].id);
18390 dc.onDragDrop(e, dropEvts[i].id);
18395 // notify about a drop that did not find a target
18396 if (isDrop && !dropEvts.length) {
18397 dc.onInvalidDrop(e);
18403 * Helper function for getting the best match from the list of drag
18404 * and drop objects returned by the drag and drop events when we are
18405 * in INTERSECT mode. It returns either the first object that the
18406 * cursor is over, or the object that has the greatest overlap with
18407 * the dragged element.
18408 * @method getBestMatch
18409 * @param {DragDrop[]} dds The array of drag and drop objects
18411 * @return {DragDrop} The best single match
18414 getBestMatch: function(dds) {
18416 // Return null if the input is not what we expect
18417 //if (!dds || !dds.length || dds.length == 0) {
18419 // If there is only one item, it wins
18420 //} else if (dds.length == 1) {
18422 var len = dds.length;
18427 // Loop through the targeted items
18428 for (var i=0; i<len; ++i) {
18430 // If the cursor is over the object, it wins. If the
18431 // cursor is over multiple matches, the first one we come
18433 if (dd.cursorIsOver) {
18436 // Otherwise the object with the most overlap wins
18439 winner.overlap.getArea() < dd.overlap.getArea()) {
18450 * Refreshes the cache of the top-left and bottom-right points of the
18451 * drag and drop objects in the specified group(s). This is in the
18452 * format that is stored in the drag and drop instance, so typical
18455 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18459 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18461 * @TODO this really should be an indexed array. Alternatively this
18462 * method could accept both.
18463 * @method refreshCache
18464 * @param {Object} groups an associative array of groups to refresh
18467 refreshCache: function(groups) {
18468 for (var sGroup in groups) {
18469 if ("string" != typeof sGroup) {
18472 for (var i in this.ids[sGroup]) {
18473 var oDD = this.ids[sGroup][i];
18475 if (this.isTypeOfDD(oDD)) {
18476 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18477 var loc = this.getLocation(oDD);
18479 this.locationCache[oDD.id] = loc;
18481 delete this.locationCache[oDD.id];
18482 // this will unregister the drag and drop object if
18483 // the element is not in a usable state
18492 * This checks to make sure an element exists and is in the DOM. The
18493 * main purpose is to handle cases where innerHTML is used to remove
18494 * drag and drop objects from the DOM. IE provides an 'unspecified
18495 * error' when trying to access the offsetParent of such an element
18497 * @param {HTMLElement} el the element to check
18498 * @return {boolean} true if the element looks usable
18501 verifyEl: function(el) {
18506 parent = el.offsetParent;
18509 parent = el.offsetParent;
18520 * Returns a Region object containing the drag and drop element's position
18521 * and size, including the padding configured for it
18522 * @method getLocation
18523 * @param {DragDrop} oDD the drag and drop object to get the
18525 * @return {Roo.lib.Region} a Region object representing the total area
18526 * the element occupies, including any padding
18527 * the instance is configured for.
18530 getLocation: function(oDD) {
18531 if (! this.isTypeOfDD(oDD)) {
18535 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18538 pos= Roo.lib.Dom.getXY(el);
18546 x2 = x1 + el.offsetWidth;
18548 y2 = y1 + el.offsetHeight;
18550 t = y1 - oDD.padding[0];
18551 r = x2 + oDD.padding[1];
18552 b = y2 + oDD.padding[2];
18553 l = x1 - oDD.padding[3];
18555 return new Roo.lib.Region( t, r, b, l );
18559 * Checks the cursor location to see if it over the target
18560 * @method isOverTarget
18561 * @param {Roo.lib.Point} pt The point to evaluate
18562 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18563 * @return {boolean} true if the mouse is over the target
18567 isOverTarget: function(pt, oTarget, intersect) {
18568 // use cache if available
18569 var loc = this.locationCache[oTarget.id];
18570 if (!loc || !this.useCache) {
18571 loc = this.getLocation(oTarget);
18572 this.locationCache[oTarget.id] = loc;
18580 oTarget.cursorIsOver = loc.contains( pt );
18582 // DragDrop is using this as a sanity check for the initial mousedown
18583 // in this case we are done. In POINT mode, if the drag obj has no
18584 // contraints, we are also done. Otherwise we need to evaluate the
18585 // location of the target as related to the actual location of the
18586 // dragged element.
18587 var dc = this.dragCurrent;
18588 if (!dc || !dc.getTargetCoord ||
18589 (!intersect && !dc.constrainX && !dc.constrainY)) {
18590 return oTarget.cursorIsOver;
18593 oTarget.overlap = null;
18595 // Get the current location of the drag element, this is the
18596 // location of the mouse event less the delta that represents
18597 // where the original mousedown happened on the element. We
18598 // need to consider constraints and ticks as well.
18599 var pos = dc.getTargetCoord(pt.x, pt.y);
18601 var el = dc.getDragEl();
18602 var curRegion = new Roo.lib.Region( pos.y,
18603 pos.x + el.offsetWidth,
18604 pos.y + el.offsetHeight,
18607 var overlap = curRegion.intersect(loc);
18610 oTarget.overlap = overlap;
18611 return (intersect) ? true : oTarget.cursorIsOver;
18618 * unload event handler
18619 * @method _onUnload
18623 _onUnload: function(e, me) {
18624 Roo.dd.DragDropMgr.unregAll();
18628 * Cleans up the drag and drop events and objects.
18633 unregAll: function() {
18635 if (this.dragCurrent) {
18637 this.dragCurrent = null;
18640 this._execOnAll("unreg", []);
18642 for (i in this.elementCache) {
18643 delete this.elementCache[i];
18646 this.elementCache = {};
18651 * A cache of DOM elements
18652 * @property elementCache
18659 * Get the wrapper for the DOM element specified
18660 * @method getElWrapper
18661 * @param {String} id the id of the element to get
18662 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18664 * @deprecated This wrapper isn't that useful
18667 getElWrapper: function(id) {
18668 var oWrapper = this.elementCache[id];
18669 if (!oWrapper || !oWrapper.el) {
18670 oWrapper = this.elementCache[id] =
18671 new this.ElementWrapper(Roo.getDom(id));
18677 * Returns the actual DOM element
18678 * @method getElement
18679 * @param {String} id the id of the elment to get
18680 * @return {Object} The element
18681 * @deprecated use Roo.getDom instead
18684 getElement: function(id) {
18685 return Roo.getDom(id);
18689 * Returns the style property for the DOM element (i.e.,
18690 * document.getElById(id).style)
18692 * @param {String} id the id of the elment to get
18693 * @return {Object} The style property of the element
18694 * @deprecated use Roo.getDom instead
18697 getCss: function(id) {
18698 var el = Roo.getDom(id);
18699 return (el) ? el.style : null;
18703 * Inner class for cached elements
18704 * @class DragDropMgr.ElementWrapper
18709 ElementWrapper: function(el) {
18714 this.el = el || null;
18719 this.id = this.el && el.id;
18721 * A reference to the style property
18724 this.css = this.el && el.style;
18728 * Returns the X position of an html element
18730 * @param el the element for which to get the position
18731 * @return {int} the X coordinate
18733 * @deprecated use Roo.lib.Dom.getX instead
18736 getPosX: function(el) {
18737 return Roo.lib.Dom.getX(el);
18741 * Returns the Y position of an html element
18743 * @param el the element for which to get the position
18744 * @return {int} the Y coordinate
18745 * @deprecated use Roo.lib.Dom.getY instead
18748 getPosY: function(el) {
18749 return Roo.lib.Dom.getY(el);
18753 * Swap two nodes. In IE, we use the native method, for others we
18754 * emulate the IE behavior
18756 * @param n1 the first node to swap
18757 * @param n2 the other node to swap
18760 swapNode: function(n1, n2) {
18764 var p = n2.parentNode;
18765 var s = n2.nextSibling;
18768 p.insertBefore(n1, n2);
18769 } else if (n2 == n1.nextSibling) {
18770 p.insertBefore(n2, n1);
18772 n1.parentNode.replaceChild(n2, n1);
18773 p.insertBefore(n1, s);
18779 * Returns the current scroll position
18780 * @method getScroll
18784 getScroll: function () {
18785 var t, l, dde=document.documentElement, db=document.body;
18786 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18788 l = dde.scrollLeft;
18795 return { top: t, left: l };
18799 * Returns the specified element style property
18801 * @param {HTMLElement} el the element
18802 * @param {string} styleProp the style property
18803 * @return {string} The value of the style property
18804 * @deprecated use Roo.lib.Dom.getStyle
18807 getStyle: function(el, styleProp) {
18808 return Roo.fly(el).getStyle(styleProp);
18812 * Gets the scrollTop
18813 * @method getScrollTop
18814 * @return {int} the document's scrollTop
18817 getScrollTop: function () { return this.getScroll().top; },
18820 * Gets the scrollLeft
18821 * @method getScrollLeft
18822 * @return {int} the document's scrollTop
18825 getScrollLeft: function () { return this.getScroll().left; },
18828 * Sets the x/y position of an element to the location of the
18831 * @param {HTMLElement} moveEl The element to move
18832 * @param {HTMLElement} targetEl The position reference element
18835 moveToEl: function (moveEl, targetEl) {
18836 var aCoord = Roo.lib.Dom.getXY(targetEl);
18837 Roo.lib.Dom.setXY(moveEl, aCoord);
18841 * Numeric array sort function
18842 * @method numericSort
18845 numericSort: function(a, b) { return (a - b); },
18849 * @property _timeoutCount
18856 * Trying to make the load order less important. Without this we get
18857 * an error if this file is loaded before the Event Utility.
18858 * @method _addListeners
18862 _addListeners: function() {
18863 var DDM = Roo.dd.DDM;
18864 if ( Roo.lib.Event && document ) {
18867 if (DDM._timeoutCount > 2000) {
18869 setTimeout(DDM._addListeners, 10);
18870 if (document && document.body) {
18871 DDM._timeoutCount += 1;
18878 * Recursively searches the immediate parent and all child nodes for
18879 * the handle element in order to determine wheter or not it was
18881 * @method handleWasClicked
18882 * @param node the html element to inspect
18885 handleWasClicked: function(node, id) {
18886 if (this.isHandle(id, node.id)) {
18889 // check to see if this is a text node child of the one we want
18890 var p = node.parentNode;
18893 if (this.isHandle(id, p.id)) {
18908 // shorter alias, save a few bytes
18909 Roo.dd.DDM = Roo.dd.DragDropMgr;
18910 Roo.dd.DDM._addListeners();
18914 * Ext JS Library 1.1.1
18915 * Copyright(c) 2006-2007, Ext JS, LLC.
18917 * Originally Released Under LGPL - original licence link has changed is not relivant.
18920 * <script type="text/javascript">
18925 * A DragDrop implementation where the linked element follows the
18926 * mouse cursor during a drag.
18927 * @extends Roo.dd.DragDrop
18929 * @param {String} id the id of the linked element
18930 * @param {String} sGroup the group of related DragDrop items
18931 * @param {object} config an object containing configurable attributes
18932 * Valid properties for DD:
18935 Roo.dd.DD = function(id, sGroup, config) {
18937 this.init(id, sGroup, config);
18941 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18944 * When set to true, the utility automatically tries to scroll the browser
18945 * window wehn a drag and drop element is dragged near the viewport boundary.
18946 * Defaults to true.
18953 * Sets the pointer offset to the distance between the linked element's top
18954 * left corner and the location the element was clicked
18955 * @method autoOffset
18956 * @param {int} iPageX the X coordinate of the click
18957 * @param {int} iPageY the Y coordinate of the click
18959 autoOffset: function(iPageX, iPageY) {
18960 var x = iPageX - this.startPageX;
18961 var y = iPageY - this.startPageY;
18962 this.setDelta(x, y);
18966 * Sets the pointer offset. You can call this directly to force the
18967 * offset to be in a particular location (e.g., pass in 0,0 to set it
18968 * to the center of the object)
18970 * @param {int} iDeltaX the distance from the left
18971 * @param {int} iDeltaY the distance from the top
18973 setDelta: function(iDeltaX, iDeltaY) {
18974 this.deltaX = iDeltaX;
18975 this.deltaY = iDeltaY;
18979 * Sets the drag element to the location of the mousedown or click event,
18980 * maintaining the cursor location relative to the location on the element
18981 * that was clicked. Override this if you want to place the element in a
18982 * location other than where the cursor is.
18983 * @method setDragElPos
18984 * @param {int} iPageX the X coordinate of the mousedown or drag event
18985 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18987 setDragElPos: function(iPageX, iPageY) {
18988 // the first time we do this, we are going to check to make sure
18989 // the element has css positioning
18991 var el = this.getDragEl();
18992 this.alignElWithMouse(el, iPageX, iPageY);
18996 * Sets the element to the location of the mousedown or click event,
18997 * maintaining the cursor location relative to the location on the element
18998 * that was clicked. Override this if you want to place the element in a
18999 * location other than where the cursor is.
19000 * @method alignElWithMouse
19001 * @param {HTMLElement} el the element to move
19002 * @param {int} iPageX the X coordinate of the mousedown or drag event
19003 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19005 alignElWithMouse: function(el, iPageX, iPageY) {
19006 var oCoord = this.getTargetCoord(iPageX, iPageY);
19007 var fly = el.dom ? el : Roo.fly(el);
19008 if (!this.deltaSetXY) {
19009 var aCoord = [oCoord.x, oCoord.y];
19011 var newLeft = fly.getLeft(true);
19012 var newTop = fly.getTop(true);
19013 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
19015 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
19018 this.cachePosition(oCoord.x, oCoord.y);
19019 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
19024 * Saves the most recent position so that we can reset the constraints and
19025 * tick marks on-demand. We need to know this so that we can calculate the
19026 * number of pixels the element is offset from its original position.
19027 * @method cachePosition
19028 * @param iPageX the current x position (optional, this just makes it so we
19029 * don't have to look it up again)
19030 * @param iPageY the current y position (optional, this just makes it so we
19031 * don't have to look it up again)
19033 cachePosition: function(iPageX, iPageY) {
19035 this.lastPageX = iPageX;
19036 this.lastPageY = iPageY;
19038 var aCoord = Roo.lib.Dom.getXY(this.getEl());
19039 this.lastPageX = aCoord[0];
19040 this.lastPageY = aCoord[1];
19045 * Auto-scroll the window if the dragged object has been moved beyond the
19046 * visible window boundary.
19047 * @method autoScroll
19048 * @param {int} x the drag element's x position
19049 * @param {int} y the drag element's y position
19050 * @param {int} h the height of the drag element
19051 * @param {int} w the width of the drag element
19054 autoScroll: function(x, y, h, w) {
19057 // The client height
19058 var clientH = Roo.lib.Dom.getViewWidth();
19060 // The client width
19061 var clientW = Roo.lib.Dom.getViewHeight();
19063 // The amt scrolled down
19064 var st = this.DDM.getScrollTop();
19066 // The amt scrolled right
19067 var sl = this.DDM.getScrollLeft();
19069 // Location of the bottom of the element
19072 // Location of the right of the element
19075 // The distance from the cursor to the bottom of the visible area,
19076 // adjusted so that we don't scroll if the cursor is beyond the
19077 // element drag constraints
19078 var toBot = (clientH + st - y - this.deltaY);
19080 // The distance from the cursor to the right of the visible area
19081 var toRight = (clientW + sl - x - this.deltaX);
19084 // How close to the edge the cursor must be before we scroll
19085 // var thresh = (document.all) ? 100 : 40;
19088 // How many pixels to scroll per autoscroll op. This helps to reduce
19089 // clunky scrolling. IE is more sensitive about this ... it needs this
19090 // value to be higher.
19091 var scrAmt = (document.all) ? 80 : 30;
19093 // Scroll down if we are near the bottom of the visible page and the
19094 // obj extends below the crease
19095 if ( bot > clientH && toBot < thresh ) {
19096 window.scrollTo(sl, st + scrAmt);
19099 // Scroll up if the window is scrolled down and the top of the object
19100 // goes above the top border
19101 if ( y < st && st > 0 && y - st < thresh ) {
19102 window.scrollTo(sl, st - scrAmt);
19105 // Scroll right if the obj is beyond the right border and the cursor is
19106 // near the border.
19107 if ( right > clientW && toRight < thresh ) {
19108 window.scrollTo(sl + scrAmt, st);
19111 // Scroll left if the window has been scrolled to the right and the obj
19112 // extends past the left border
19113 if ( x < sl && sl > 0 && x - sl < thresh ) {
19114 window.scrollTo(sl - scrAmt, st);
19120 * Finds the location the element should be placed if we want to move
19121 * it to where the mouse location less the click offset would place us.
19122 * @method getTargetCoord
19123 * @param {int} iPageX the X coordinate of the click
19124 * @param {int} iPageY the Y coordinate of the click
19125 * @return an object that contains the coordinates (Object.x and Object.y)
19128 getTargetCoord: function(iPageX, iPageY) {
19131 var x = iPageX - this.deltaX;
19132 var y = iPageY - this.deltaY;
19134 if (this.constrainX) {
19135 if (x < this.minX) { x = this.minX; }
19136 if (x > this.maxX) { x = this.maxX; }
19139 if (this.constrainY) {
19140 if (y < this.minY) { y = this.minY; }
19141 if (y > this.maxY) { y = this.maxY; }
19144 x = this.getTick(x, this.xTicks);
19145 y = this.getTick(y, this.yTicks);
19152 * Sets up config options specific to this class. Overrides
19153 * Roo.dd.DragDrop, but all versions of this method through the
19154 * inheritance chain are called
19156 applyConfig: function() {
19157 Roo.dd.DD.superclass.applyConfig.call(this);
19158 this.scroll = (this.config.scroll !== false);
19162 * Event that fires prior to the onMouseDown event. Overrides
19165 b4MouseDown: function(e) {
19166 // this.resetConstraints();
19167 this.autoOffset(e.getPageX(),
19172 * Event that fires prior to the onDrag event. Overrides
19175 b4Drag: function(e) {
19176 this.setDragElPos(e.getPageX(),
19180 toString: function() {
19181 return ("DD " + this.id);
19184 //////////////////////////////////////////////////////////////////////////
19185 // Debugging ygDragDrop events that can be overridden
19186 //////////////////////////////////////////////////////////////////////////
19188 startDrag: function(x, y) {
19191 onDrag: function(e) {
19194 onDragEnter: function(e, id) {
19197 onDragOver: function(e, id) {
19200 onDragOut: function(e, id) {
19203 onDragDrop: function(e, id) {
19206 endDrag: function(e) {
19213 * Ext JS Library 1.1.1
19214 * Copyright(c) 2006-2007, Ext JS, LLC.
19216 * Originally Released Under LGPL - original licence link has changed is not relivant.
19219 * <script type="text/javascript">
19223 * @class Roo.dd.DDProxy
19224 * A DragDrop implementation that inserts an empty, bordered div into
19225 * the document that follows the cursor during drag operations. At the time of
19226 * the click, the frame div is resized to the dimensions of the linked html
19227 * element, and moved to the exact location of the linked element.
19229 * References to the "frame" element refer to the single proxy element that
19230 * was created to be dragged in place of all DDProxy elements on the
19233 * @extends Roo.dd.DD
19235 * @param {String} id the id of the linked html element
19236 * @param {String} sGroup the group of related DragDrop objects
19237 * @param {object} config an object containing configurable attributes
19238 * Valid properties for DDProxy in addition to those in DragDrop:
19239 * resizeFrame, centerFrame, dragElId
19241 Roo.dd.DDProxy = function(id, sGroup, config) {
19243 this.init(id, sGroup, config);
19249 * The default drag frame div id
19250 * @property Roo.dd.DDProxy.dragElId
19254 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19256 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19259 * By default we resize the drag frame to be the same size as the element
19260 * we want to drag (this is to get the frame effect). We can turn it off
19261 * if we want a different behavior.
19262 * @property resizeFrame
19268 * By default the frame is positioned exactly where the drag element is, so
19269 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19270 * you do not have constraints on the obj is to have the drag frame centered
19271 * around the cursor. Set centerFrame to true for this effect.
19272 * @property centerFrame
19275 centerFrame: false,
19278 * Creates the proxy element if it does not yet exist
19279 * @method createFrame
19281 createFrame: function() {
19283 var body = document.body;
19285 if (!body || !body.firstChild) {
19286 setTimeout( function() { self.createFrame(); }, 50 );
19290 var div = this.getDragEl();
19293 div = document.createElement("div");
19294 div.id = this.dragElId;
19297 s.position = "absolute";
19298 s.visibility = "hidden";
19300 s.border = "2px solid #aaa";
19303 // appendChild can blow up IE if invoked prior to the window load event
19304 // while rendering a table. It is possible there are other scenarios
19305 // that would cause this to happen as well.
19306 body.insertBefore(div, body.firstChild);
19311 * Initialization for the drag frame element. Must be called in the
19312 * constructor of all subclasses
19313 * @method initFrame
19315 initFrame: function() {
19316 this.createFrame();
19319 applyConfig: function() {
19320 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19322 this.resizeFrame = (this.config.resizeFrame !== false);
19323 this.centerFrame = (this.config.centerFrame);
19324 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19328 * Resizes the drag frame to the dimensions of the clicked object, positions
19329 * it over the object, and finally displays it
19330 * @method showFrame
19331 * @param {int} iPageX X click position
19332 * @param {int} iPageY Y click position
19335 showFrame: function(iPageX, iPageY) {
19336 var el = this.getEl();
19337 var dragEl = this.getDragEl();
19338 var s = dragEl.style;
19340 this._resizeProxy();
19342 if (this.centerFrame) {
19343 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19344 Math.round(parseInt(s.height, 10)/2) );
19347 this.setDragElPos(iPageX, iPageY);
19349 Roo.fly(dragEl).show();
19353 * The proxy is automatically resized to the dimensions of the linked
19354 * element when a drag is initiated, unless resizeFrame is set to false
19355 * @method _resizeProxy
19358 _resizeProxy: function() {
19359 if (this.resizeFrame) {
19360 var el = this.getEl();
19361 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19365 // overrides Roo.dd.DragDrop
19366 b4MouseDown: function(e) {
19367 var x = e.getPageX();
19368 var y = e.getPageY();
19369 this.autoOffset(x, y);
19370 this.setDragElPos(x, y);
19373 // overrides Roo.dd.DragDrop
19374 b4StartDrag: function(x, y) {
19375 // show the drag frame
19376 this.showFrame(x, y);
19379 // overrides Roo.dd.DragDrop
19380 b4EndDrag: function(e) {
19381 Roo.fly(this.getDragEl()).hide();
19384 // overrides Roo.dd.DragDrop
19385 // By default we try to move the element to the last location of the frame.
19386 // This is so that the default behavior mirrors that of Roo.dd.DD.
19387 endDrag: function(e) {
19389 var lel = this.getEl();
19390 var del = this.getDragEl();
19392 // Show the drag frame briefly so we can get its position
19393 del.style.visibility = "";
19396 // Hide the linked element before the move to get around a Safari
19398 lel.style.visibility = "hidden";
19399 Roo.dd.DDM.moveToEl(lel, del);
19400 del.style.visibility = "hidden";
19401 lel.style.visibility = "";
19406 beforeMove : function(){
19410 afterDrag : function(){
19414 toString: function() {
19415 return ("DDProxy " + this.id);
19421 * Ext JS Library 1.1.1
19422 * Copyright(c) 2006-2007, Ext JS, LLC.
19424 * Originally Released Under LGPL - original licence link has changed is not relivant.
19427 * <script type="text/javascript">
19431 * @class Roo.dd.DDTarget
19432 * A DragDrop implementation that does not move, but can be a drop
19433 * target. You would get the same result by simply omitting implementation
19434 * for the event callbacks, but this way we reduce the processing cost of the
19435 * event listener and the callbacks.
19436 * @extends Roo.dd.DragDrop
19438 * @param {String} id the id of the element that is a drop target
19439 * @param {String} sGroup the group of related DragDrop objects
19440 * @param {object} config an object containing configurable attributes
19441 * Valid properties for DDTarget in addition to those in
19445 Roo.dd.DDTarget = function(id, sGroup, config) {
19447 this.initTarget(id, sGroup, config);
19449 if (config.listeners || config.events) {
19450 Roo.dd.DragDrop.superclass.constructor.call(this, {
19451 listeners : config.listeners || {},
19452 events : config.events || {}
19457 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19458 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19459 toString: function() {
19460 return ("DDTarget " + this.id);
19465 * Ext JS Library 1.1.1
19466 * Copyright(c) 2006-2007, Ext JS, LLC.
19468 * Originally Released Under LGPL - original licence link has changed is not relivant.
19471 * <script type="text/javascript">
19476 * @class Roo.dd.ScrollManager
19477 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19478 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19481 Roo.dd.ScrollManager = function(){
19482 var ddm = Roo.dd.DragDropMgr;
19489 var onStop = function(e){
19494 var triggerRefresh = function(){
19495 if(ddm.dragCurrent){
19496 ddm.refreshCache(ddm.dragCurrent.groups);
19500 var doScroll = function(){
19501 if(ddm.dragCurrent){
19502 var dds = Roo.dd.ScrollManager;
19504 if(proc.el.scroll(proc.dir, dds.increment)){
19508 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19513 var clearProc = function(){
19515 clearInterval(proc.id);
19522 var startProc = function(el, dir){
19523 Roo.log('scroll startproc');
19527 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19530 var onFire = function(e, isDrop){
19532 if(isDrop || !ddm.dragCurrent){ return; }
19533 var dds = Roo.dd.ScrollManager;
19534 if(!dragEl || dragEl != ddm.dragCurrent){
19535 dragEl = ddm.dragCurrent;
19536 // refresh regions on drag start
19537 dds.refreshCache();
19540 var xy = Roo.lib.Event.getXY(e);
19541 var pt = new Roo.lib.Point(xy[0], xy[1]);
19542 for(var id in els){
19543 var el = els[id], r = el._region;
19544 if(r && r.contains(pt) && el.isScrollable()){
19545 if(r.bottom - pt.y <= dds.thresh){
19547 startProc(el, "down");
19550 }else if(r.right - pt.x <= dds.thresh){
19552 startProc(el, "left");
19555 }else if(pt.y - r.top <= dds.thresh){
19557 startProc(el, "up");
19560 }else if(pt.x - r.left <= dds.thresh){
19562 startProc(el, "right");
19571 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19572 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19576 * Registers new overflow element(s) to auto scroll
19577 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19579 register : function(el){
19580 if(el instanceof Array){
19581 for(var i = 0, len = el.length; i < len; i++) {
19582 this.register(el[i]);
19588 Roo.dd.ScrollManager.els = els;
19592 * Unregisters overflow element(s) so they are no longer scrolled
19593 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19595 unregister : function(el){
19596 if(el instanceof Array){
19597 for(var i = 0, len = el.length; i < len; i++) {
19598 this.unregister(el[i]);
19607 * The number of pixels from the edge of a container the pointer needs to be to
19608 * trigger scrolling (defaults to 25)
19614 * The number of pixels to scroll in each scroll increment (defaults to 50)
19620 * The frequency of scrolls in milliseconds (defaults to 500)
19626 * True to animate the scroll (defaults to true)
19632 * The animation duration in seconds -
19633 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19639 * Manually trigger a cache refresh.
19641 refreshCache : function(){
19642 for(var id in els){
19643 if(typeof els[id] == 'object'){ // for people extending the object prototype
19644 els[id]._region = els[id].getRegion();
19651 * Ext JS Library 1.1.1
19652 * Copyright(c) 2006-2007, Ext JS, LLC.
19654 * Originally Released Under LGPL - original licence link has changed is not relivant.
19657 * <script type="text/javascript">
19662 * @class Roo.dd.Registry
19663 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19664 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19667 Roo.dd.Registry = function(){
19670 var autoIdSeed = 0;
19672 var getId = function(el, autogen){
19673 if(typeof el == "string"){
19677 if(!id && autogen !== false){
19678 id = "roodd-" + (++autoIdSeed);
19686 * Register a drag drop element
19687 * @param {String|HTMLElement} element The id or DOM node to register
19688 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19689 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19690 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19691 * populated in the data object (if applicable):
19693 Value Description<br />
19694 --------- ------------------------------------------<br />
19695 handles Array of DOM nodes that trigger dragging<br />
19696 for the element being registered<br />
19697 isHandle True if the element passed in triggers<br />
19698 dragging itself, else false
19701 register : function(el, data){
19703 if(typeof el == "string"){
19704 el = document.getElementById(el);
19707 elements[getId(el)] = data;
19708 if(data.isHandle !== false){
19709 handles[data.ddel.id] = data;
19712 var hs = data.handles;
19713 for(var i = 0, len = hs.length; i < len; i++){
19714 handles[getId(hs[i])] = data;
19720 * Unregister a drag drop element
19721 * @param {String|HTMLElement} element The id or DOM node to unregister
19723 unregister : function(el){
19724 var id = getId(el, false);
19725 var data = elements[id];
19727 delete elements[id];
19729 var hs = data.handles;
19730 for(var i = 0, len = hs.length; i < len; i++){
19731 delete handles[getId(hs[i], false)];
19738 * Returns the handle registered for a DOM Node by id
19739 * @param {String|HTMLElement} id The DOM node or id to look up
19740 * @return {Object} handle The custom handle data
19742 getHandle : function(id){
19743 if(typeof id != "string"){ // must be element?
19746 return handles[id];
19750 * Returns the handle that is registered for the DOM node that is the target of the event
19751 * @param {Event} e The event
19752 * @return {Object} handle The custom handle data
19754 getHandleFromEvent : function(e){
19755 var t = Roo.lib.Event.getTarget(e);
19756 return t ? handles[t.id] : null;
19760 * Returns a custom data object that is registered for a DOM node by id
19761 * @param {String|HTMLElement} id The DOM node or id to look up
19762 * @return {Object} data The custom data
19764 getTarget : function(id){
19765 if(typeof id != "string"){ // must be element?
19768 return elements[id];
19772 * Returns a custom data object that is registered for the DOM node that is the target of the event
19773 * @param {Event} e The event
19774 * @return {Object} data The custom data
19776 getTargetFromEvent : function(e){
19777 var t = Roo.lib.Event.getTarget(e);
19778 return t ? elements[t.id] || handles[t.id] : null;
19783 * Ext JS Library 1.1.1
19784 * Copyright(c) 2006-2007, Ext JS, LLC.
19786 * Originally Released Under LGPL - original licence link has changed is not relivant.
19789 * <script type="text/javascript">
19794 * @class Roo.dd.StatusProxy
19795 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19796 * default drag proxy used by all Roo.dd components.
19798 * @param {Object} config
19800 Roo.dd.StatusProxy = function(config){
19801 Roo.apply(this, config);
19802 this.id = this.id || Roo.id();
19803 this.el = new Roo.Layer({
19805 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19806 {tag: "div", cls: "x-dd-drop-icon"},
19807 {tag: "div", cls: "x-dd-drag-ghost"}
19810 shadow: !config || config.shadow !== false
19812 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19813 this.dropStatus = this.dropNotAllowed;
19816 Roo.dd.StatusProxy.prototype = {
19818 * @cfg {String} dropAllowed
19819 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19821 dropAllowed : "x-dd-drop-ok",
19823 * @cfg {String} dropNotAllowed
19824 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19826 dropNotAllowed : "x-dd-drop-nodrop",
19829 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19830 * over the current target element.
19831 * @param {String} cssClass The css class for the new drop status indicator image
19833 setStatus : function(cssClass){
19834 cssClass = cssClass || this.dropNotAllowed;
19835 if(this.dropStatus != cssClass){
19836 this.el.replaceClass(this.dropStatus, cssClass);
19837 this.dropStatus = cssClass;
19842 * Resets the status indicator to the default dropNotAllowed value
19843 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19845 reset : function(clearGhost){
19846 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19847 this.dropStatus = this.dropNotAllowed;
19849 this.ghost.update("");
19854 * Updates the contents of the ghost element
19855 * @param {String} html The html that will replace the current innerHTML of the ghost element
19857 update : function(html){
19858 if(typeof html == "string"){
19859 this.ghost.update(html);
19861 this.ghost.update("");
19862 html.style.margin = "0";
19863 this.ghost.dom.appendChild(html);
19865 // ensure float = none set?? cant remember why though.
19866 var el = this.ghost.dom.firstChild;
19868 Roo.fly(el).setStyle('float', 'none');
19873 * Returns the underlying proxy {@link Roo.Layer}
19874 * @return {Roo.Layer} el
19876 getEl : function(){
19881 * Returns the ghost element
19882 * @return {Roo.Element} el
19884 getGhost : function(){
19890 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19892 hide : function(clear){
19900 * Stops the repair animation if it's currently running
19903 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19909 * Displays this proxy
19916 * Force the Layer to sync its shadow and shim positions to the element
19923 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19924 * invalid drop operation by the item being dragged.
19925 * @param {Array} xy The XY position of the element ([x, y])
19926 * @param {Function} callback The function to call after the repair is complete
19927 * @param {Object} scope The scope in which to execute the callback
19929 repair : function(xy, callback, scope){
19930 this.callback = callback;
19931 this.scope = scope;
19932 if(xy && this.animRepair !== false){
19933 this.el.addClass("x-dd-drag-repair");
19934 this.el.hideUnders(true);
19935 this.anim = this.el.shift({
19936 duration: this.repairDuration || .5,
19940 callback: this.afterRepair,
19944 this.afterRepair();
19949 afterRepair : function(){
19951 if(typeof this.callback == "function"){
19952 this.callback.call(this.scope || this);
19954 this.callback = null;
19959 * Ext JS Library 1.1.1
19960 * Copyright(c) 2006-2007, Ext JS, LLC.
19962 * Originally Released Under LGPL - original licence link has changed is not relivant.
19965 * <script type="text/javascript">
19969 * @class Roo.dd.DragSource
19970 * @extends Roo.dd.DDProxy
19971 * A simple class that provides the basic implementation needed to make any element draggable.
19973 * @param {String/HTMLElement/Element} el The container element
19974 * @param {Object} config
19976 Roo.dd.DragSource = function(el, config){
19977 this.el = Roo.get(el);
19978 this.dragData = {};
19980 Roo.apply(this, config);
19983 this.proxy = new Roo.dd.StatusProxy();
19986 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
19987 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
19989 this.dragging = false;
19992 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
19994 * @cfg {String} dropAllowed
19995 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
19997 dropAllowed : "x-dd-drop-ok",
19999 * @cfg {String} dropNotAllowed
20000 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20002 dropNotAllowed : "x-dd-drop-nodrop",
20005 * Returns the data object associated with this drag source
20006 * @return {Object} data An object containing arbitrary data
20008 getDragData : function(e){
20009 return this.dragData;
20013 onDragEnter : function(e, id){
20014 var target = Roo.dd.DragDropMgr.getDDById(id);
20015 this.cachedTarget = target;
20016 if(this.beforeDragEnter(target, e, id) !== false){
20017 if(target.isNotifyTarget){
20018 var status = target.notifyEnter(this, e, this.dragData);
20019 this.proxy.setStatus(status);
20021 this.proxy.setStatus(this.dropAllowed);
20024 if(this.afterDragEnter){
20026 * An empty function by default, but provided so that you can perform a custom action
20027 * when the dragged item enters the drop target by providing an implementation.
20028 * @param {Roo.dd.DragDrop} target The drop target
20029 * @param {Event} e The event object
20030 * @param {String} id The id of the dragged element
20031 * @method afterDragEnter
20033 this.afterDragEnter(target, e, id);
20039 * An empty function by default, but provided so that you can perform a custom action
20040 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
20041 * @param {Roo.dd.DragDrop} target The drop target
20042 * @param {Event} e The event object
20043 * @param {String} id The id of the dragged element
20044 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20046 beforeDragEnter : function(target, e, id){
20051 alignElWithMouse: function() {
20052 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
20057 onDragOver : function(e, id){
20058 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20059 if(this.beforeDragOver(target, e, id) !== false){
20060 if(target.isNotifyTarget){
20061 var status = target.notifyOver(this, e, this.dragData);
20062 this.proxy.setStatus(status);
20065 if(this.afterDragOver){
20067 * An empty function by default, but provided so that you can perform a custom action
20068 * while the dragged item is over the drop target by providing an implementation.
20069 * @param {Roo.dd.DragDrop} target The drop target
20070 * @param {Event} e The event object
20071 * @param {String} id The id of the dragged element
20072 * @method afterDragOver
20074 this.afterDragOver(target, e, id);
20080 * An empty function by default, but provided so that you can perform a custom action
20081 * while the dragged item is over the drop target and optionally cancel the onDragOver.
20082 * @param {Roo.dd.DragDrop} target The drop target
20083 * @param {Event} e The event object
20084 * @param {String} id The id of the dragged element
20085 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20087 beforeDragOver : function(target, e, id){
20092 onDragOut : function(e, id){
20093 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20094 if(this.beforeDragOut(target, e, id) !== false){
20095 if(target.isNotifyTarget){
20096 target.notifyOut(this, e, this.dragData);
20098 this.proxy.reset();
20099 if(this.afterDragOut){
20101 * An empty function by default, but provided so that you can perform a custom action
20102 * after the dragged item is dragged out of the target without dropping.
20103 * @param {Roo.dd.DragDrop} target The drop target
20104 * @param {Event} e The event object
20105 * @param {String} id The id of the dragged element
20106 * @method afterDragOut
20108 this.afterDragOut(target, e, id);
20111 this.cachedTarget = null;
20115 * An empty function by default, but provided so that you can perform a custom action before the dragged
20116 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20117 * @param {Roo.dd.DragDrop} target The drop target
20118 * @param {Event} e The event object
20119 * @param {String} id The id of the dragged element
20120 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20122 beforeDragOut : function(target, e, id){
20127 onDragDrop : function(e, id){
20128 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20129 if(this.beforeDragDrop(target, e, id) !== false){
20130 if(target.isNotifyTarget){
20131 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20132 this.onValidDrop(target, e, id);
20134 this.onInvalidDrop(target, e, id);
20137 this.onValidDrop(target, e, id);
20140 if(this.afterDragDrop){
20142 * An empty function by default, but provided so that you can perform a custom action
20143 * after a valid drag drop has occurred by providing an implementation.
20144 * @param {Roo.dd.DragDrop} target The drop target
20145 * @param {Event} e The event object
20146 * @param {String} id The id of the dropped element
20147 * @method afterDragDrop
20149 this.afterDragDrop(target, e, id);
20152 delete this.cachedTarget;
20156 * An empty function by default, but provided so that you can perform a custom action before the dragged
20157 * item is dropped onto the target and optionally cancel the onDragDrop.
20158 * @param {Roo.dd.DragDrop} target The drop target
20159 * @param {Event} e The event object
20160 * @param {String} id The id of the dragged element
20161 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20163 beforeDragDrop : function(target, e, id){
20168 onValidDrop : function(target, e, id){
20170 if(this.afterValidDrop){
20172 * An empty function by default, but provided so that you can perform a custom action
20173 * after a valid drop has occurred by providing an implementation.
20174 * @param {Object} target The target DD
20175 * @param {Event} e The event object
20176 * @param {String} id The id of the dropped element
20177 * @method afterInvalidDrop
20179 this.afterValidDrop(target, e, id);
20184 getRepairXY : function(e, data){
20185 return this.el.getXY();
20189 onInvalidDrop : function(target, e, id){
20190 this.beforeInvalidDrop(target, e, id);
20191 if(this.cachedTarget){
20192 if(this.cachedTarget.isNotifyTarget){
20193 this.cachedTarget.notifyOut(this, e, this.dragData);
20195 this.cacheTarget = null;
20197 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20199 if(this.afterInvalidDrop){
20201 * An empty function by default, but provided so that you can perform a custom action
20202 * after an invalid drop has occurred by providing an implementation.
20203 * @param {Event} e The event object
20204 * @param {String} id The id of the dropped element
20205 * @method afterInvalidDrop
20207 this.afterInvalidDrop(e, id);
20212 afterRepair : function(){
20214 this.el.highlight(this.hlColor || "c3daf9");
20216 this.dragging = false;
20220 * An empty function by default, but provided so that you can perform a custom action after an invalid
20221 * drop has occurred.
20222 * @param {Roo.dd.DragDrop} target The drop target
20223 * @param {Event} e The event object
20224 * @param {String} id The id of the dragged element
20225 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20227 beforeInvalidDrop : function(target, e, id){
20232 handleMouseDown : function(e){
20233 if(this.dragging) {
20236 var data = this.getDragData(e);
20237 if(data && this.onBeforeDrag(data, e) !== false){
20238 this.dragData = data;
20240 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20245 * An empty function by default, but provided so that you can perform a custom action before the initial
20246 * drag event begins and optionally cancel it.
20247 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20248 * @param {Event} e The event object
20249 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20251 onBeforeDrag : function(data, e){
20256 * An empty function by default, but provided so that you can perform a custom action once the initial
20257 * drag event has begun. The drag cannot be canceled from this function.
20258 * @param {Number} x The x position of the click on the dragged object
20259 * @param {Number} y The y position of the click on the dragged object
20261 onStartDrag : Roo.emptyFn,
20263 // private - YUI override
20264 startDrag : function(x, y){
20265 this.proxy.reset();
20266 this.dragging = true;
20267 this.proxy.update("");
20268 this.onInitDrag(x, y);
20273 onInitDrag : function(x, y){
20274 var clone = this.el.dom.cloneNode(true);
20275 clone.id = Roo.id(); // prevent duplicate ids
20276 this.proxy.update(clone);
20277 this.onStartDrag(x, y);
20282 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20283 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20285 getProxy : function(){
20290 * Hides the drag source's {@link Roo.dd.StatusProxy}
20292 hideProxy : function(){
20294 this.proxy.reset(true);
20295 this.dragging = false;
20299 triggerCacheRefresh : function(){
20300 Roo.dd.DDM.refreshCache(this.groups);
20303 // private - override to prevent hiding
20304 b4EndDrag: function(e) {
20307 // private - override to prevent moving
20308 endDrag : function(e){
20309 this.onEndDrag(this.dragData, e);
20313 onEndDrag : function(data, e){
20316 // private - pin to cursor
20317 autoOffset : function(x, y) {
20318 this.setDelta(-12, -20);
20322 * Ext JS Library 1.1.1
20323 * Copyright(c) 2006-2007, Ext JS, LLC.
20325 * Originally Released Under LGPL - original licence link has changed is not relivant.
20328 * <script type="text/javascript">
20333 * @class Roo.dd.DropTarget
20334 * @extends Roo.dd.DDTarget
20335 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20336 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20338 * @param {String/HTMLElement/Element} el The container element
20339 * @param {Object} config
20341 Roo.dd.DropTarget = function(el, config){
20342 this.el = Roo.get(el);
20344 var listeners = false; ;
20345 if (config && config.listeners) {
20346 listeners= config.listeners;
20347 delete config.listeners;
20349 Roo.apply(this, config);
20351 if(this.containerScroll){
20352 Roo.dd.ScrollManager.register(this.el);
20356 * @scope Roo.dd.DropTarget
20361 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20362 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20363 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20365 * IMPORTANT : it should set this.overClass and this.dropAllowed
20367 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20368 * @param {Event} e The event
20369 * @param {Object} data An object containing arbitrary data supplied by the drag source
20375 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20376 * This method will be called on every mouse movement while the drag source is over the drop target.
20377 * This default implementation simply returns the dropAllowed config value.
20379 * IMPORTANT : it should set this.dropAllowed
20381 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20382 * @param {Event} e The event
20383 * @param {Object} data An object containing arbitrary data supplied by the drag source
20389 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20390 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20391 * overClass (if any) from the drop element.
20393 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20394 * @param {Event} e The event
20395 * @param {Object} data An object containing arbitrary data supplied by the drag source
20401 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20402 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20403 * implementation that does something to process the drop event and returns true so that the drag source's
20404 * repair action does not run.
20406 * IMPORTANT : it should set this.success
20408 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20409 * @param {Event} e The event
20410 * @param {Object} data An object containing arbitrary data supplied by the drag source
20416 Roo.dd.DropTarget.superclass.constructor.call( this,
20418 this.ddGroup || this.group,
20421 listeners : listeners || {}
20429 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20431 * @cfg {String} overClass
20432 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20435 * @cfg {String} ddGroup
20436 * The drag drop group to handle drop events for
20440 * @cfg {String} dropAllowed
20441 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20443 dropAllowed : "x-dd-drop-ok",
20445 * @cfg {String} dropNotAllowed
20446 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20448 dropNotAllowed : "x-dd-drop-nodrop",
20450 * @cfg {boolean} success
20451 * set this after drop listener..
20455 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20456 * if the drop point is valid for over/enter..
20463 isNotifyTarget : true,
20468 notifyEnter : function(dd, e, data)
20471 this.fireEvent('enter', dd, e, data);
20472 if(this.overClass){
20473 this.el.addClass(this.overClass);
20475 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20476 this.valid ? this.dropAllowed : this.dropNotAllowed
20483 notifyOver : function(dd, e, data)
20486 this.fireEvent('over', dd, e, data);
20487 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20488 this.valid ? this.dropAllowed : this.dropNotAllowed
20495 notifyOut : function(dd, e, data)
20497 this.fireEvent('out', dd, e, data);
20498 if(this.overClass){
20499 this.el.removeClass(this.overClass);
20506 notifyDrop : function(dd, e, data)
20508 this.success = false;
20509 this.fireEvent('drop', dd, e, data);
20510 return this.success;
20514 * Ext JS Library 1.1.1
20515 * Copyright(c) 2006-2007, Ext JS, LLC.
20517 * Originally Released Under LGPL - original licence link has changed is not relivant.
20520 * <script type="text/javascript">
20525 * @class Roo.dd.DragZone
20526 * @extends Roo.dd.DragSource
20527 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20528 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20530 * @param {String/HTMLElement/Element} el The container element
20531 * @param {Object} config
20533 Roo.dd.DragZone = function(el, config){
20534 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20535 if(this.containerScroll){
20536 Roo.dd.ScrollManager.register(this.el);
20540 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20542 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20543 * for auto scrolling during drag operations.
20546 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20547 * method after a failed drop (defaults to "c3daf9" - light blue)
20551 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20552 * for a valid target to drag based on the mouse down. Override this method
20553 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20554 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20555 * @param {EventObject} e The mouse down event
20556 * @return {Object} The dragData
20558 getDragData : function(e){
20559 return Roo.dd.Registry.getHandleFromEvent(e);
20563 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20564 * this.dragData.ddel
20565 * @param {Number} x The x position of the click on the dragged object
20566 * @param {Number} y The y position of the click on the dragged object
20567 * @return {Boolean} true to continue the drag, false to cancel
20569 onInitDrag : function(x, y){
20570 this.proxy.update(this.dragData.ddel.cloneNode(true));
20571 this.onStartDrag(x, y);
20576 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20578 afterRepair : function(){
20580 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20582 this.dragging = false;
20586 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20587 * the XY of this.dragData.ddel
20588 * @param {EventObject} e The mouse up event
20589 * @return {Array} The xy location (e.g. [100, 200])
20591 getRepairXY : function(e){
20592 return Roo.Element.fly(this.dragData.ddel).getXY();
20596 * Ext JS Library 1.1.1
20597 * Copyright(c) 2006-2007, Ext JS, LLC.
20599 * Originally Released Under LGPL - original licence link has changed is not relivant.
20602 * <script type="text/javascript">
20605 * @class Roo.dd.DropZone
20606 * @extends Roo.dd.DropTarget
20607 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20608 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20610 * @param {String/HTMLElement/Element} el The container element
20611 * @param {Object} config
20613 Roo.dd.DropZone = function(el, config){
20614 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20617 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20619 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20620 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20621 * provide your own custom lookup.
20622 * @param {Event} e The event
20623 * @return {Object} data The custom data
20625 getTargetFromEvent : function(e){
20626 return Roo.dd.Registry.getTargetFromEvent(e);
20630 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20631 * that it has registered. This method has no default implementation and should be overridden to provide
20632 * node-specific processing if necessary.
20633 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20634 * {@link #getTargetFromEvent} for this node)
20635 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20636 * @param {Event} e The event
20637 * @param {Object} data An object containing arbitrary data supplied by the drag source
20639 onNodeEnter : function(n, dd, e, data){
20644 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20645 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20646 * overridden to provide the proper feedback.
20647 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20648 * {@link #getTargetFromEvent} for this node)
20649 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20650 * @param {Event} e The event
20651 * @param {Object} data An object containing arbitrary data supplied by the drag source
20652 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20653 * underlying {@link Roo.dd.StatusProxy} can be updated
20655 onNodeOver : function(n, dd, e, data){
20656 return this.dropAllowed;
20660 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20661 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20662 * node-specific processing if necessary.
20663 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20664 * {@link #getTargetFromEvent} for this node)
20665 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20666 * @param {Event} e The event
20667 * @param {Object} data An object containing arbitrary data supplied by the drag source
20669 onNodeOut : function(n, dd, e, data){
20674 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20675 * the drop node. The default implementation returns false, so it should be overridden to provide the
20676 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20677 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20678 * {@link #getTargetFromEvent} for this node)
20679 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20680 * @param {Event} e The event
20681 * @param {Object} data An object containing arbitrary data supplied by the drag source
20682 * @return {Boolean} True if the drop was valid, else false
20684 onNodeDrop : function(n, dd, e, data){
20689 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20690 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20691 * it should be overridden to provide the proper feedback if necessary.
20692 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20693 * @param {Event} e The event
20694 * @param {Object} data An object containing arbitrary data supplied by the drag source
20695 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20696 * underlying {@link Roo.dd.StatusProxy} can be updated
20698 onContainerOver : function(dd, e, data){
20699 return this.dropNotAllowed;
20703 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20704 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20705 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20706 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20707 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20708 * @param {Event} e The event
20709 * @param {Object} data An object containing arbitrary data supplied by the drag source
20710 * @return {Boolean} True if the drop was valid, else false
20712 onContainerDrop : function(dd, e, data){
20717 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20718 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20719 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20720 * you should override this method and provide a custom implementation.
20721 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20722 * @param {Event} e The event
20723 * @param {Object} data An object containing arbitrary data supplied by the drag source
20724 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20725 * underlying {@link Roo.dd.StatusProxy} can be updated
20727 notifyEnter : function(dd, e, data){
20728 return this.dropNotAllowed;
20732 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20733 * This method will be called on every mouse movement while the drag source is over the drop zone.
20734 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20735 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20736 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20737 * registered node, it will call {@link #onContainerOver}.
20738 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20739 * @param {Event} e The event
20740 * @param {Object} data An object containing arbitrary data supplied by the drag source
20741 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20742 * underlying {@link Roo.dd.StatusProxy} can be updated
20744 notifyOver : function(dd, e, data){
20745 var n = this.getTargetFromEvent(e);
20746 if(!n){ // not over valid drop target
20747 if(this.lastOverNode){
20748 this.onNodeOut(this.lastOverNode, dd, e, data);
20749 this.lastOverNode = null;
20751 return this.onContainerOver(dd, e, data);
20753 if(this.lastOverNode != n){
20754 if(this.lastOverNode){
20755 this.onNodeOut(this.lastOverNode, dd, e, data);
20757 this.onNodeEnter(n, dd, e, data);
20758 this.lastOverNode = n;
20760 return this.onNodeOver(n, dd, e, data);
20764 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20765 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20766 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20767 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20768 * @param {Event} e The event
20769 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20771 notifyOut : function(dd, e, data){
20772 if(this.lastOverNode){
20773 this.onNodeOut(this.lastOverNode, dd, e, data);
20774 this.lastOverNode = null;
20779 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20780 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20781 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20782 * otherwise it will call {@link #onContainerDrop}.
20783 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20784 * @param {Event} e The event
20785 * @param {Object} data An object containing arbitrary data supplied by the drag source
20786 * @return {Boolean} True if the drop was valid, else false
20788 notifyDrop : function(dd, e, data){
20789 if(this.lastOverNode){
20790 this.onNodeOut(this.lastOverNode, dd, e, data);
20791 this.lastOverNode = null;
20793 var n = this.getTargetFromEvent(e);
20795 this.onNodeDrop(n, dd, e, data) :
20796 this.onContainerDrop(dd, e, data);
20800 triggerCacheRefresh : function(){
20801 Roo.dd.DDM.refreshCache(this.groups);
20805 * Ext JS Library 1.1.1
20806 * Copyright(c) 2006-2007, Ext JS, LLC.
20808 * Originally Released Under LGPL - original licence link has changed is not relivant.
20811 * <script type="text/javascript">
20816 * @class Roo.data.SortTypes
20818 * Defines the default sorting (casting?) comparison functions used when sorting data.
20820 Roo.data.SortTypes = {
20822 * Default sort that does nothing
20823 * @param {Mixed} s The value being converted
20824 * @return {Mixed} The comparison value
20826 none : function(s){
20831 * The regular expression used to strip tags
20835 stripTagsRE : /<\/?[^>]+>/gi,
20838 * Strips all HTML tags to sort on text only
20839 * @param {Mixed} s The value being converted
20840 * @return {String} The comparison value
20842 asText : function(s){
20843 return String(s).replace(this.stripTagsRE, "");
20847 * Strips all HTML tags to sort on text only - Case insensitive
20848 * @param {Mixed} s The value being converted
20849 * @return {String} The comparison value
20851 asUCText : function(s){
20852 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20856 * Case insensitive string
20857 * @param {Mixed} s The value being converted
20858 * @return {String} The comparison value
20860 asUCString : function(s) {
20861 return String(s).toUpperCase();
20866 * @param {Mixed} s The value being converted
20867 * @return {Number} The comparison value
20869 asDate : function(s) {
20873 if(s instanceof Date){
20874 return s.getTime();
20876 return Date.parse(String(s));
20881 * @param {Mixed} s The value being converted
20882 * @return {Float} The comparison value
20884 asFloat : function(s) {
20885 var val = parseFloat(String(s).replace(/,/g, ""));
20886 if(isNaN(val)) val = 0;
20892 * @param {Mixed} s The value being converted
20893 * @return {Number} The comparison value
20895 asInt : function(s) {
20896 var val = parseInt(String(s).replace(/,/g, ""));
20897 if(isNaN(val)) val = 0;
20902 * Ext JS Library 1.1.1
20903 * Copyright(c) 2006-2007, Ext JS, LLC.
20905 * Originally Released Under LGPL - original licence link has changed is not relivant.
20908 * <script type="text/javascript">
20912 * @class Roo.data.Record
20913 * Instances of this class encapsulate both record <em>definition</em> information, and record
20914 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20915 * to access Records cached in an {@link Roo.data.Store} object.<br>
20917 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20918 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20921 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20923 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20924 * {@link #create}. The parameters are the same.
20925 * @param {Array} data An associative Array of data values keyed by the field name.
20926 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20927 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20928 * not specified an integer id is generated.
20930 Roo.data.Record = function(data, id){
20931 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20936 * Generate a constructor for a specific record layout.
20937 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20938 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20939 * Each field definition object may contain the following properties: <ul>
20940 * <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,
20941 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20942 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20943 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20944 * is being used, then this is a string containing the javascript expression to reference the data relative to
20945 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20946 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20947 * this may be omitted.</p></li>
20948 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20949 * <ul><li>auto (Default, implies no conversion)</li>
20954 * <li>date</li></ul></p></li>
20955 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20956 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20957 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20958 * by the Reader into an object that will be stored in the Record. It is passed the
20959 * following parameters:<ul>
20960 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20962 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20964 * <br>usage:<br><pre><code>
20965 var TopicRecord = Roo.data.Record.create(
20966 {name: 'title', mapping: 'topic_title'},
20967 {name: 'author', mapping: 'username'},
20968 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20969 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20970 {name: 'lastPoster', mapping: 'user2'},
20971 {name: 'excerpt', mapping: 'post_text'}
20974 var myNewRecord = new TopicRecord({
20975 title: 'Do my job please',
20978 lastPost: new Date(),
20979 lastPoster: 'Animal',
20980 excerpt: 'No way dude!'
20982 myStore.add(myNewRecord);
20987 Roo.data.Record.create = function(o){
20988 var f = function(){
20989 f.superclass.constructor.apply(this, arguments);
20991 Roo.extend(f, Roo.data.Record);
20992 var p = f.prototype;
20993 p.fields = new Roo.util.MixedCollection(false, function(field){
20996 for(var i = 0, len = o.length; i < len; i++){
20997 p.fields.add(new Roo.data.Field(o[i]));
20999 f.getField = function(name){
21000 return p.fields.get(name);
21005 Roo.data.Record.AUTO_ID = 1000;
21006 Roo.data.Record.EDIT = 'edit';
21007 Roo.data.Record.REJECT = 'reject';
21008 Roo.data.Record.COMMIT = 'commit';
21010 Roo.data.Record.prototype = {
21012 * Readonly flag - true if this record has been modified.
21021 join : function(store){
21022 this.store = store;
21026 * Set the named field to the specified value.
21027 * @param {String} name The name of the field to set.
21028 * @param {Object} value The value to set the field to.
21030 set : function(name, value){
21031 if(this.data[name] == value){
21035 if(!this.modified){
21036 this.modified = {};
21038 if(typeof this.modified[name] == 'undefined'){
21039 this.modified[name] = this.data[name];
21041 this.data[name] = value;
21042 if(!this.editing && this.store){
21043 this.store.afterEdit(this);
21048 * Get the value of the named field.
21049 * @param {String} name The name of the field to get the value of.
21050 * @return {Object} The value of the field.
21052 get : function(name){
21053 return this.data[name];
21057 beginEdit : function(){
21058 this.editing = true;
21059 this.modified = {};
21063 cancelEdit : function(){
21064 this.editing = false;
21065 delete this.modified;
21069 endEdit : function(){
21070 this.editing = false;
21071 if(this.dirty && this.store){
21072 this.store.afterEdit(this);
21077 * Usually called by the {@link Roo.data.Store} which owns the Record.
21078 * Rejects all changes made to the Record since either creation, or the last commit operation.
21079 * Modified fields are reverted to their original values.
21081 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21082 * of reject operations.
21084 reject : function(){
21085 var m = this.modified;
21087 if(typeof m[n] != "function"){
21088 this.data[n] = m[n];
21091 this.dirty = false;
21092 delete this.modified;
21093 this.editing = false;
21095 this.store.afterReject(this);
21100 * Usually called by the {@link Roo.data.Store} which owns the Record.
21101 * Commits all changes made to the Record since either creation, or the last commit operation.
21103 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21104 * of commit operations.
21106 commit : function(){
21107 this.dirty = false;
21108 delete this.modified;
21109 this.editing = false;
21111 this.store.afterCommit(this);
21116 hasError : function(){
21117 return this.error != null;
21121 clearError : function(){
21126 * Creates a copy of this record.
21127 * @param {String} id (optional) A new record id if you don't want to use this record's id
21130 copy : function(newId) {
21131 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21135 * Ext JS Library 1.1.1
21136 * Copyright(c) 2006-2007, Ext JS, LLC.
21138 * Originally Released Under LGPL - original licence link has changed is not relivant.
21141 * <script type="text/javascript">
21147 * @class Roo.data.Store
21148 * @extends Roo.util.Observable
21149 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21150 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21152 * 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
21153 * has no knowledge of the format of the data returned by the Proxy.<br>
21155 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21156 * instances from the data object. These records are cached and made available through accessor functions.
21158 * Creates a new Store.
21159 * @param {Object} config A config object containing the objects needed for the Store to access data,
21160 * and read the data into Records.
21162 Roo.data.Store = function(config){
21163 this.data = new Roo.util.MixedCollection(false);
21164 this.data.getKey = function(o){
21167 this.baseParams = {};
21169 this.paramNames = {
21174 "multisort" : "_multisort"
21177 if(config && config.data){
21178 this.inlineData = config.data;
21179 delete config.data;
21182 Roo.apply(this, config);
21184 if(this.reader){ // reader passed
21185 this.reader = Roo.factory(this.reader, Roo.data);
21186 this.reader.xmodule = this.xmodule || false;
21187 if(!this.recordType){
21188 this.recordType = this.reader.recordType;
21190 if(this.reader.onMetaChange){
21191 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21195 if(this.recordType){
21196 this.fields = this.recordType.prototype.fields;
21198 this.modified = [];
21202 * @event datachanged
21203 * Fires when the data cache has changed, and a widget which is using this Store
21204 * as a Record cache should refresh its view.
21205 * @param {Store} this
21207 datachanged : true,
21209 * @event metachange
21210 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21211 * @param {Store} this
21212 * @param {Object} meta The JSON metadata
21217 * Fires when Records have been added to the Store
21218 * @param {Store} this
21219 * @param {Roo.data.Record[]} records The array of Records added
21220 * @param {Number} index The index at which the record(s) were added
21225 * Fires when a Record has been removed from the Store
21226 * @param {Store} this
21227 * @param {Roo.data.Record} record The Record that was removed
21228 * @param {Number} index The index at which the record was removed
21233 * Fires when a Record has been updated
21234 * @param {Store} this
21235 * @param {Roo.data.Record} record The Record that was updated
21236 * @param {String} operation The update operation being performed. Value may be one of:
21238 Roo.data.Record.EDIT
21239 Roo.data.Record.REJECT
21240 Roo.data.Record.COMMIT
21246 * Fires when the data cache has been cleared.
21247 * @param {Store} this
21251 * @event beforeload
21252 * Fires before a request is made for a new data object. If the beforeload handler returns false
21253 * the load action will be canceled.
21254 * @param {Store} this
21255 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21259 * @event beforeloadadd
21260 * Fires after a new set of Records has been loaded.
21261 * @param {Store} this
21262 * @param {Roo.data.Record[]} records The Records that were loaded
21263 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21265 beforeloadadd : true,
21268 * Fires after a new set of Records has been loaded, before they are added to the store.
21269 * @param {Store} this
21270 * @param {Roo.data.Record[]} records The Records that were loaded
21271 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21272 * @params {Object} return from reader
21276 * @event loadexception
21277 * Fires if an exception occurs in the Proxy during loading.
21278 * Called with the signature of the Proxy's "loadexception" event.
21279 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21282 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21283 * @param {Object} load options
21284 * @param {Object} jsonData from your request (normally this contains the Exception)
21286 loadexception : true
21290 this.proxy = Roo.factory(this.proxy, Roo.data);
21291 this.proxy.xmodule = this.xmodule || false;
21292 this.relayEvents(this.proxy, ["loadexception"]);
21294 this.sortToggle = {};
21295 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21297 Roo.data.Store.superclass.constructor.call(this);
21299 if(this.inlineData){
21300 this.loadData(this.inlineData);
21301 delete this.inlineData;
21305 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21307 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21308 * without a remote query - used by combo/forms at present.
21312 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21315 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21318 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21319 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21322 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21323 * on any HTTP request
21326 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21329 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21333 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21334 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21336 remoteSort : false,
21339 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21340 * loaded or when a record is removed. (defaults to false).
21342 pruneModifiedRecords : false,
21345 lastOptions : null,
21348 * Add Records to the Store and fires the add event.
21349 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21351 add : function(records){
21352 records = [].concat(records);
21353 for(var i = 0, len = records.length; i < len; i++){
21354 records[i].join(this);
21356 var index = this.data.length;
21357 this.data.addAll(records);
21358 this.fireEvent("add", this, records, index);
21362 * Remove a Record from the Store and fires the remove event.
21363 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21365 remove : function(record){
21366 var index = this.data.indexOf(record);
21367 this.data.removeAt(index);
21368 if(this.pruneModifiedRecords){
21369 this.modified.remove(record);
21371 this.fireEvent("remove", this, record, index);
21375 * Remove all Records from the Store and fires the clear event.
21377 removeAll : function(){
21379 if(this.pruneModifiedRecords){
21380 this.modified = [];
21382 this.fireEvent("clear", this);
21386 * Inserts Records to the Store at the given index and fires the add event.
21387 * @param {Number} index The start index at which to insert the passed Records.
21388 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21390 insert : function(index, records){
21391 records = [].concat(records);
21392 for(var i = 0, len = records.length; i < len; i++){
21393 this.data.insert(index, records[i]);
21394 records[i].join(this);
21396 this.fireEvent("add", this, records, index);
21400 * Get the index within the cache of the passed Record.
21401 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21402 * @return {Number} The index of the passed Record. Returns -1 if not found.
21404 indexOf : function(record){
21405 return this.data.indexOf(record);
21409 * Get the index within the cache of the Record with the passed id.
21410 * @param {String} id The id of the Record to find.
21411 * @return {Number} The index of the Record. Returns -1 if not found.
21413 indexOfId : function(id){
21414 return this.data.indexOfKey(id);
21418 * Get the Record with the specified id.
21419 * @param {String} id The id of the Record to find.
21420 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21422 getById : function(id){
21423 return this.data.key(id);
21427 * Get the Record at the specified index.
21428 * @param {Number} index The index of the Record to find.
21429 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21431 getAt : function(index){
21432 return this.data.itemAt(index);
21436 * Returns a range of Records between specified indices.
21437 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21438 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21439 * @return {Roo.data.Record[]} An array of Records
21441 getRange : function(start, end){
21442 return this.data.getRange(start, end);
21446 storeOptions : function(o){
21447 o = Roo.apply({}, o);
21450 this.lastOptions = o;
21454 * Loads the Record cache from the configured Proxy using the configured Reader.
21456 * If using remote paging, then the first load call must specify the <em>start</em>
21457 * and <em>limit</em> properties in the options.params property to establish the initial
21458 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21460 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21461 * and this call will return before the new data has been loaded. Perform any post-processing
21462 * in a callback function, or in a "load" event handler.</strong>
21464 * @param {Object} options An object containing properties which control loading options:<ul>
21465 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21466 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21467 * passed the following arguments:<ul>
21468 * <li>r : Roo.data.Record[]</li>
21469 * <li>options: Options object from the load call</li>
21470 * <li>success: Boolean success indicator</li></ul></li>
21471 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21472 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21475 load : function(options){
21476 options = options || {};
21477 if(this.fireEvent("beforeload", this, options) !== false){
21478 this.storeOptions(options);
21479 var p = Roo.apply(options.params || {}, this.baseParams);
21480 // if meta was not loaded from remote source.. try requesting it.
21481 if (!this.reader.metaFromRemote) {
21482 p._requestMeta = 1;
21484 if(this.sortInfo && this.remoteSort){
21485 var pn = this.paramNames;
21486 p[pn["sort"]] = this.sortInfo.field;
21487 p[pn["dir"]] = this.sortInfo.direction;
21489 if (this.multiSort) {
21490 var pn = this.paramNames;
21491 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21494 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21499 * Reloads the Record cache from the configured Proxy using the configured Reader and
21500 * the options from the last load operation performed.
21501 * @param {Object} options (optional) An object containing properties which may override the options
21502 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21503 * the most recently used options are reused).
21505 reload : function(options){
21506 this.load(Roo.applyIf(options||{}, this.lastOptions));
21510 // Called as a callback by the Reader during a load operation.
21511 loadRecords : function(o, options, success){
21512 if(!o || success === false){
21513 if(success !== false){
21514 this.fireEvent("load", this, [], options, o);
21516 if(options.callback){
21517 options.callback.call(options.scope || this, [], options, false);
21521 // if data returned failure - throw an exception.
21522 if (o.success === false) {
21523 // show a message if no listener is registered.
21524 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21525 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21527 // loadmask wil be hooked into this..
21528 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21531 var r = o.records, t = o.totalRecords || r.length;
21533 this.fireEvent("beforeloadadd", this, r, options, o);
21535 if(!options || options.add !== true){
21536 if(this.pruneModifiedRecords){
21537 this.modified = [];
21539 for(var i = 0, len = r.length; i < len; i++){
21543 this.data = this.snapshot;
21544 delete this.snapshot;
21547 this.data.addAll(r);
21548 this.totalLength = t;
21550 this.fireEvent("datachanged", this);
21552 this.totalLength = Math.max(t, this.data.length+r.length);
21555 this.fireEvent("load", this, r, options, o);
21556 if(options.callback){
21557 options.callback.call(options.scope || this, r, options, true);
21563 * Loads data from a passed data block. A Reader which understands the format of the data
21564 * must have been configured in the constructor.
21565 * @param {Object} data The data block from which to read the Records. The format of the data expected
21566 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21567 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21569 loadData : function(o, append){
21570 var r = this.reader.readRecords(o);
21571 this.loadRecords(r, {add: append}, true);
21575 * Gets the number of cached records.
21577 * <em>If using paging, this may not be the total size of the dataset. If the data object
21578 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21579 * the data set size</em>
21581 getCount : function(){
21582 return this.data.length || 0;
21586 * Gets the total number of records in the dataset as returned by the server.
21588 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21589 * the dataset size</em>
21591 getTotalCount : function(){
21592 return this.totalLength || 0;
21596 * Returns the sort state of the Store as an object with two properties:
21598 field {String} The name of the field by which the Records are sorted
21599 direction {String} The sort order, "ASC" or "DESC"
21602 getSortState : function(){
21603 return this.sortInfo;
21607 applySort : function(){
21608 if(this.sortInfo && !this.remoteSort){
21609 var s = this.sortInfo, f = s.field;
21610 var st = this.fields.get(f).sortType;
21611 var fn = function(r1, r2){
21612 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21613 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21615 this.data.sort(s.direction, fn);
21616 if(this.snapshot && this.snapshot != this.data){
21617 this.snapshot.sort(s.direction, fn);
21623 * Sets the default sort column and order to be used by the next load operation.
21624 * @param {String} fieldName The name of the field to sort by.
21625 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21627 setDefaultSort : function(field, dir){
21628 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21632 * Sort the Records.
21633 * If remote sorting is used, the sort is performed on the server, and the cache is
21634 * reloaded. If local sorting is used, the cache is sorted internally.
21635 * @param {String} fieldName The name of the field to sort by.
21636 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21638 sort : function(fieldName, dir){
21639 var f = this.fields.get(fieldName);
21641 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21643 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21644 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21649 this.sortToggle[f.name] = dir;
21650 this.sortInfo = {field: f.name, direction: dir};
21651 if(!this.remoteSort){
21653 this.fireEvent("datachanged", this);
21655 this.load(this.lastOptions);
21660 * Calls the specified function for each of the Records in the cache.
21661 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21662 * Returning <em>false</em> aborts and exits the iteration.
21663 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21665 each : function(fn, scope){
21666 this.data.each(fn, scope);
21670 * Gets all records modified since the last commit. Modified records are persisted across load operations
21671 * (e.g., during paging).
21672 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21674 getModifiedRecords : function(){
21675 return this.modified;
21679 createFilterFn : function(property, value, anyMatch){
21680 if(!value.exec){ // not a regex
21681 value = String(value);
21682 if(value.length == 0){
21685 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21687 return function(r){
21688 return value.test(r.data[property]);
21693 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21694 * @param {String} property A field on your records
21695 * @param {Number} start The record index to start at (defaults to 0)
21696 * @param {Number} end The last record index to include (defaults to length - 1)
21697 * @return {Number} The sum
21699 sum : function(property, start, end){
21700 var rs = this.data.items, v = 0;
21701 start = start || 0;
21702 end = (end || end === 0) ? end : rs.length-1;
21704 for(var i = start; i <= end; i++){
21705 v += (rs[i].data[property] || 0);
21711 * Filter the records by a specified property.
21712 * @param {String} field A field on your records
21713 * @param {String/RegExp} value Either a string that the field
21714 * should start with or a RegExp to test against the field
21715 * @param {Boolean} anyMatch True to match any part not just the beginning
21717 filter : function(property, value, anyMatch){
21718 var fn = this.createFilterFn(property, value, anyMatch);
21719 return fn ? this.filterBy(fn) : this.clearFilter();
21723 * Filter by a function. The specified function will be called with each
21724 * record in this data source. If the function returns true the record is included,
21725 * otherwise it is filtered.
21726 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21727 * @param {Object} scope (optional) The scope of the function (defaults to this)
21729 filterBy : function(fn, scope){
21730 this.snapshot = this.snapshot || this.data;
21731 this.data = this.queryBy(fn, scope||this);
21732 this.fireEvent("datachanged", this);
21736 * Query the records by a specified property.
21737 * @param {String} field A field on your records
21738 * @param {String/RegExp} value Either a string that the field
21739 * should start with or a RegExp to test against the field
21740 * @param {Boolean} anyMatch True to match any part not just the beginning
21741 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21743 query : function(property, value, anyMatch){
21744 var fn = this.createFilterFn(property, value, anyMatch);
21745 return fn ? this.queryBy(fn) : this.data.clone();
21749 * Query by a function. The specified function will be called with each
21750 * record in this data source. If the function returns true the record is included
21752 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21753 * @param {Object} scope (optional) The scope of the function (defaults to this)
21754 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21756 queryBy : function(fn, scope){
21757 var data = this.snapshot || this.data;
21758 return data.filterBy(fn, scope||this);
21762 * Collects unique values for a particular dataIndex from this store.
21763 * @param {String} dataIndex The property to collect
21764 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21765 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21766 * @return {Array} An array of the unique values
21768 collect : function(dataIndex, allowNull, bypassFilter){
21769 var d = (bypassFilter === true && this.snapshot) ?
21770 this.snapshot.items : this.data.items;
21771 var v, sv, r = [], l = {};
21772 for(var i = 0, len = d.length; i < len; i++){
21773 v = d[i].data[dataIndex];
21775 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21784 * Revert to a view of the Record cache with no filtering applied.
21785 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21787 clearFilter : function(suppressEvent){
21788 if(this.snapshot && this.snapshot != this.data){
21789 this.data = this.snapshot;
21790 delete this.snapshot;
21791 if(suppressEvent !== true){
21792 this.fireEvent("datachanged", this);
21798 afterEdit : function(record){
21799 if(this.modified.indexOf(record) == -1){
21800 this.modified.push(record);
21802 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21806 afterReject : function(record){
21807 this.modified.remove(record);
21808 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21812 afterCommit : function(record){
21813 this.modified.remove(record);
21814 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21818 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21819 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21821 commitChanges : function(){
21822 var m = this.modified.slice(0);
21823 this.modified = [];
21824 for(var i = 0, len = m.length; i < len; i++){
21830 * Cancel outstanding changes on all changed records.
21832 rejectChanges : function(){
21833 var m = this.modified.slice(0);
21834 this.modified = [];
21835 for(var i = 0, len = m.length; i < len; i++){
21840 onMetaChange : function(meta, rtype, o){
21841 this.recordType = rtype;
21842 this.fields = rtype.prototype.fields;
21843 delete this.snapshot;
21844 this.sortInfo = meta.sortInfo || this.sortInfo;
21845 this.modified = [];
21846 this.fireEvent('metachange', this, this.reader.meta);
21849 moveIndex : function(data, type)
21851 var index = this.indexOf(data);
21853 var newIndex = index + type;
21857 this.insert(newIndex, data);
21862 * Ext JS Library 1.1.1
21863 * Copyright(c) 2006-2007, Ext JS, LLC.
21865 * Originally Released Under LGPL - original licence link has changed is not relivant.
21868 * <script type="text/javascript">
21872 * @class Roo.data.SimpleStore
21873 * @extends Roo.data.Store
21874 * Small helper class to make creating Stores from Array data easier.
21875 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21876 * @cfg {Array} fields An array of field definition objects, or field name strings.
21877 * @cfg {Array} data The multi-dimensional array of data
21879 * @param {Object} config
21881 Roo.data.SimpleStore = function(config){
21882 Roo.data.SimpleStore.superclass.constructor.call(this, {
21884 reader: new Roo.data.ArrayReader({
21887 Roo.data.Record.create(config.fields)
21889 proxy : new Roo.data.MemoryProxy(config.data)
21893 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21895 * Ext JS Library 1.1.1
21896 * Copyright(c) 2006-2007, Ext JS, LLC.
21898 * Originally Released Under LGPL - original licence link has changed is not relivant.
21901 * <script type="text/javascript">
21906 * @extends Roo.data.Store
21907 * @class Roo.data.JsonStore
21908 * Small helper class to make creating Stores for JSON data easier. <br/>
21910 var store = new Roo.data.JsonStore({
21911 url: 'get-images.php',
21913 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21916 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21917 * JsonReader and HttpProxy (unless inline data is provided).</b>
21918 * @cfg {Array} fields An array of field definition objects, or field name strings.
21920 * @param {Object} config
21922 Roo.data.JsonStore = function(c){
21923 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21924 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21925 reader: new Roo.data.JsonReader(c, c.fields)
21928 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21930 * Ext JS Library 1.1.1
21931 * Copyright(c) 2006-2007, Ext JS, LLC.
21933 * Originally Released Under LGPL - original licence link has changed is not relivant.
21936 * <script type="text/javascript">
21940 Roo.data.Field = function(config){
21941 if(typeof config == "string"){
21942 config = {name: config};
21944 Roo.apply(this, config);
21947 this.type = "auto";
21950 var st = Roo.data.SortTypes;
21951 // named sortTypes are supported, here we look them up
21952 if(typeof this.sortType == "string"){
21953 this.sortType = st[this.sortType];
21956 // set default sortType for strings and dates
21957 if(!this.sortType){
21960 this.sortType = st.asUCString;
21963 this.sortType = st.asDate;
21966 this.sortType = st.none;
21971 var stripRe = /[\$,%]/g;
21973 // prebuilt conversion function for this field, instead of
21974 // switching every time we're reading a value
21976 var cv, dateFormat = this.dateFormat;
21981 cv = function(v){ return v; };
21984 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
21988 return v !== undefined && v !== null && v !== '' ?
21989 parseInt(String(v).replace(stripRe, ""), 10) : '';
21994 return v !== undefined && v !== null && v !== '' ?
21995 parseFloat(String(v).replace(stripRe, ""), 10) : '';
22000 cv = function(v){ return v === true || v === "true" || v == 1; };
22007 if(v instanceof Date){
22011 if(dateFormat == "timestamp"){
22012 return new Date(v*1000);
22014 return Date.parseDate(v, dateFormat);
22016 var parsed = Date.parse(v);
22017 return parsed ? new Date(parsed) : null;
22026 Roo.data.Field.prototype = {
22034 * Ext JS Library 1.1.1
22035 * Copyright(c) 2006-2007, Ext JS, LLC.
22037 * Originally Released Under LGPL - original licence link has changed is not relivant.
22040 * <script type="text/javascript">
22043 // Base class for reading structured data from a data source. This class is intended to be
22044 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
22047 * @class Roo.data.DataReader
22048 * Base class for reading structured data from a data source. This class is intended to be
22049 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
22052 Roo.data.DataReader = function(meta, recordType){
22056 this.recordType = recordType instanceof Array ?
22057 Roo.data.Record.create(recordType) : recordType;
22060 Roo.data.DataReader.prototype = {
22062 * Create an empty record
22063 * @param {Object} data (optional) - overlay some values
22064 * @return {Roo.data.Record} record created.
22066 newRow : function(d) {
22068 this.recordType.prototype.fields.each(function(c) {
22070 case 'int' : da[c.name] = 0; break;
22071 case 'date' : da[c.name] = new Date(); break;
22072 case 'float' : da[c.name] = 0.0; break;
22073 case 'boolean' : da[c.name] = false; break;
22074 default : da[c.name] = ""; break;
22078 return new this.recordType(Roo.apply(da, d));
22083 * Ext JS Library 1.1.1
22084 * Copyright(c) 2006-2007, Ext JS, LLC.
22086 * Originally Released Under LGPL - original licence link has changed is not relivant.
22089 * <script type="text/javascript">
22093 * @class Roo.data.DataProxy
22094 * @extends Roo.data.Observable
22095 * This class is an abstract base class for implementations which provide retrieval of
22096 * unformatted data objects.<br>
22098 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22099 * (of the appropriate type which knows how to parse the data object) to provide a block of
22100 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22102 * Custom implementations must implement the load method as described in
22103 * {@link Roo.data.HttpProxy#load}.
22105 Roo.data.DataProxy = function(){
22108 * @event beforeload
22109 * Fires before a network request is made to retrieve a data object.
22110 * @param {Object} This DataProxy object.
22111 * @param {Object} params The params parameter to the load function.
22116 * Fires before the load method's callback is called.
22117 * @param {Object} This DataProxy object.
22118 * @param {Object} o The data object.
22119 * @param {Object} arg The callback argument object passed to the load function.
22123 * @event loadexception
22124 * Fires if an Exception occurs during data retrieval.
22125 * @param {Object} This DataProxy object.
22126 * @param {Object} o The data object.
22127 * @param {Object} arg The callback argument object passed to the load function.
22128 * @param {Object} e The Exception.
22130 loadexception : true
22132 Roo.data.DataProxy.superclass.constructor.call(this);
22135 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22138 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22142 * Ext JS Library 1.1.1
22143 * Copyright(c) 2006-2007, Ext JS, LLC.
22145 * Originally Released Under LGPL - original licence link has changed is not relivant.
22148 * <script type="text/javascript">
22151 * @class Roo.data.MemoryProxy
22152 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22153 * to the Reader when its load method is called.
22155 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22157 Roo.data.MemoryProxy = function(data){
22161 Roo.data.MemoryProxy.superclass.constructor.call(this);
22165 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22167 * Load data from the requested source (in this case an in-memory
22168 * data object passed to the constructor), read the data object into
22169 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22170 * process that block using the passed callback.
22171 * @param {Object} params This parameter is not used by the MemoryProxy class.
22172 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22173 * object into a block of Roo.data.Records.
22174 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22175 * The function must be passed <ul>
22176 * <li>The Record block object</li>
22177 * <li>The "arg" argument from the load function</li>
22178 * <li>A boolean success indicator</li>
22180 * @param {Object} scope The scope in which to call the callback
22181 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22183 load : function(params, reader, callback, scope, arg){
22184 params = params || {};
22187 result = reader.readRecords(this.data);
22189 this.fireEvent("loadexception", this, arg, null, e);
22190 callback.call(scope, null, arg, false);
22193 callback.call(scope, result, arg, true);
22197 update : function(params, records){
22202 * Ext JS Library 1.1.1
22203 * Copyright(c) 2006-2007, Ext JS, LLC.
22205 * Originally Released Under LGPL - original licence link has changed is not relivant.
22208 * <script type="text/javascript">
22211 * @class Roo.data.HttpProxy
22212 * @extends Roo.data.DataProxy
22213 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22214 * configured to reference a certain URL.<br><br>
22216 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22217 * from which the running page was served.<br><br>
22219 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22221 * Be aware that to enable the browser to parse an XML document, the server must set
22222 * the Content-Type header in the HTTP response to "text/xml".
22224 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22225 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22226 * will be used to make the request.
22228 Roo.data.HttpProxy = function(conn){
22229 Roo.data.HttpProxy.superclass.constructor.call(this);
22230 // is conn a conn config or a real conn?
22232 this.useAjax = !conn || !conn.events;
22236 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22237 // thse are take from connection...
22240 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22243 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22244 * extra parameters to each request made by this object. (defaults to undefined)
22247 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22248 * to each request made by this object. (defaults to undefined)
22251 * @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)
22254 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22257 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22263 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22267 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22268 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22269 * a finer-grained basis than the DataProxy events.
22271 getConnection : function(){
22272 return this.useAjax ? Roo.Ajax : this.conn;
22276 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22277 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22278 * process that block using the passed callback.
22279 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22280 * for the request to the remote server.
22281 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22282 * object into a block of Roo.data.Records.
22283 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22284 * The function must be passed <ul>
22285 * <li>The Record block object</li>
22286 * <li>The "arg" argument from the load function</li>
22287 * <li>A boolean success indicator</li>
22289 * @param {Object} scope The scope in which to call the callback
22290 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22292 load : function(params, reader, callback, scope, arg){
22293 if(this.fireEvent("beforeload", this, params) !== false){
22295 params : params || {},
22297 callback : callback,
22302 callback : this.loadResponse,
22306 Roo.applyIf(o, this.conn);
22307 if(this.activeRequest){
22308 Roo.Ajax.abort(this.activeRequest);
22310 this.activeRequest = Roo.Ajax.request(o);
22312 this.conn.request(o);
22315 callback.call(scope||this, null, arg, false);
22320 loadResponse : function(o, success, response){
22321 delete this.activeRequest;
22323 this.fireEvent("loadexception", this, o, response);
22324 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22329 result = o.reader.read(response);
22331 this.fireEvent("loadexception", this, o, response, e);
22332 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22336 this.fireEvent("load", this, o, o.request.arg);
22337 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22341 update : function(dataSet){
22346 updateResponse : function(dataSet){
22351 * Ext JS Library 1.1.1
22352 * Copyright(c) 2006-2007, Ext JS, LLC.
22354 * Originally Released Under LGPL - original licence link has changed is not relivant.
22357 * <script type="text/javascript">
22361 * @class Roo.data.ScriptTagProxy
22362 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22363 * other than the originating domain of the running page.<br><br>
22365 * <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
22366 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22368 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22369 * source code that is used as the source inside a <script> tag.<br><br>
22371 * In order for the browser to process the returned data, the server must wrap the data object
22372 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22373 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22374 * depending on whether the callback name was passed:
22377 boolean scriptTag = false;
22378 String cb = request.getParameter("callback");
22381 response.setContentType("text/javascript");
22383 response.setContentType("application/x-json");
22385 Writer out = response.getWriter();
22387 out.write(cb + "(");
22389 out.print(dataBlock.toJsonString());
22396 * @param {Object} config A configuration object.
22398 Roo.data.ScriptTagProxy = function(config){
22399 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22400 Roo.apply(this, config);
22401 this.head = document.getElementsByTagName("head")[0];
22404 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22406 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22408 * @cfg {String} url The URL from which to request the data object.
22411 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22415 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22416 * the server the name of the callback function set up by the load call to process the returned data object.
22417 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22418 * javascript output which calls this named function passing the data object as its only parameter.
22420 callbackParam : "callback",
22422 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22423 * name to the request.
22428 * Load data from the configured URL, read the data object into
22429 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22430 * process that block using the passed callback.
22431 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22432 * for the request to the remote server.
22433 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22434 * object into a block of Roo.data.Records.
22435 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22436 * The function must be passed <ul>
22437 * <li>The Record block object</li>
22438 * <li>The "arg" argument from the load function</li>
22439 * <li>A boolean success indicator</li>
22441 * @param {Object} scope The scope in which to call the callback
22442 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22444 load : function(params, reader, callback, scope, arg){
22445 if(this.fireEvent("beforeload", this, params) !== false){
22447 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22449 var url = this.url;
22450 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22452 url += "&_dc=" + (new Date().getTime());
22454 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22457 cb : "stcCallback"+transId,
22458 scriptId : "stcScript"+transId,
22462 callback : callback,
22468 window[trans.cb] = function(o){
22469 conn.handleResponse(o, trans);
22472 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22474 if(this.autoAbort !== false){
22478 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22480 var script = document.createElement("script");
22481 script.setAttribute("src", url);
22482 script.setAttribute("type", "text/javascript");
22483 script.setAttribute("id", trans.scriptId);
22484 this.head.appendChild(script);
22486 this.trans = trans;
22488 callback.call(scope||this, null, arg, false);
22493 isLoading : function(){
22494 return this.trans ? true : false;
22498 * Abort the current server request.
22500 abort : function(){
22501 if(this.isLoading()){
22502 this.destroyTrans(this.trans);
22507 destroyTrans : function(trans, isLoaded){
22508 this.head.removeChild(document.getElementById(trans.scriptId));
22509 clearTimeout(trans.timeoutId);
22511 window[trans.cb] = undefined;
22513 delete window[trans.cb];
22516 // if hasn't been loaded, wait for load to remove it to prevent script error
22517 window[trans.cb] = function(){
22518 window[trans.cb] = undefined;
22520 delete window[trans.cb];
22527 handleResponse : function(o, trans){
22528 this.trans = false;
22529 this.destroyTrans(trans, true);
22532 result = trans.reader.readRecords(o);
22534 this.fireEvent("loadexception", this, o, trans.arg, e);
22535 trans.callback.call(trans.scope||window, null, trans.arg, false);
22538 this.fireEvent("load", this, o, trans.arg);
22539 trans.callback.call(trans.scope||window, result, trans.arg, true);
22543 handleFailure : function(trans){
22544 this.trans = false;
22545 this.destroyTrans(trans, false);
22546 this.fireEvent("loadexception", this, null, trans.arg);
22547 trans.callback.call(trans.scope||window, null, trans.arg, false);
22551 * Ext JS Library 1.1.1
22552 * Copyright(c) 2006-2007, Ext JS, LLC.
22554 * Originally Released Under LGPL - original licence link has changed is not relivant.
22557 * <script type="text/javascript">
22561 * @class Roo.data.JsonReader
22562 * @extends Roo.data.DataReader
22563 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22564 * based on mappings in a provided Roo.data.Record constructor.
22566 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22567 * in the reply previously.
22572 var RecordDef = Roo.data.Record.create([
22573 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22574 {name: 'occupation'} // This field will use "occupation" as the mapping.
22576 var myReader = new Roo.data.JsonReader({
22577 totalProperty: "results", // The property which contains the total dataset size (optional)
22578 root: "rows", // The property which contains an Array of row objects
22579 id: "id" // The property within each row object that provides an ID for the record (optional)
22583 * This would consume a JSON file like this:
22585 { 'results': 2, 'rows': [
22586 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22587 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22590 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22591 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22592 * paged from the remote server.
22593 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22594 * @cfg {String} root name of the property which contains the Array of row objects.
22595 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22597 * Create a new JsonReader
22598 * @param {Object} meta Metadata configuration options
22599 * @param {Object} recordType Either an Array of field definition objects,
22600 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22602 Roo.data.JsonReader = function(meta, recordType){
22605 // set some defaults:
22606 Roo.applyIf(meta, {
22607 totalProperty: 'total',
22608 successProperty : 'success',
22613 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22615 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22618 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22619 * Used by Store query builder to append _requestMeta to params.
22622 metaFromRemote : false,
22624 * This method is only used by a DataProxy which has retrieved data from a remote server.
22625 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22626 * @return {Object} data A data block which is used by an Roo.data.Store object as
22627 * a cache of Roo.data.Records.
22629 read : function(response){
22630 var json = response.responseText;
22632 var o = /* eval:var:o */ eval("("+json+")");
22634 throw {message: "JsonReader.read: Json object not found"};
22640 this.metaFromRemote = true;
22641 this.meta = o.metaData;
22642 this.recordType = Roo.data.Record.create(o.metaData.fields);
22643 this.onMetaChange(this.meta, this.recordType, o);
22645 return this.readRecords(o);
22648 // private function a store will implement
22649 onMetaChange : function(meta, recordType, o){
22656 simpleAccess: function(obj, subsc) {
22663 getJsonAccessor: function(){
22665 return function(expr) {
22667 return(re.test(expr))
22668 ? new Function("obj", "return obj." + expr)
22673 return Roo.emptyFn;
22678 * Create a data block containing Roo.data.Records from an XML document.
22679 * @param {Object} o An object which contains an Array of row objects in the property specified
22680 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22681 * which contains the total size of the dataset.
22682 * @return {Object} data A data block which is used by an Roo.data.Store object as
22683 * a cache of Roo.data.Records.
22685 readRecords : function(o){
22687 * After any data loads, the raw JSON data is available for further custom processing.
22691 var s = this.meta, Record = this.recordType,
22692 f = Record.prototype.fields, fi = f.items, fl = f.length;
22694 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22696 if(s.totalProperty) {
22697 this.getTotal = this.getJsonAccessor(s.totalProperty);
22699 if(s.successProperty) {
22700 this.getSuccess = this.getJsonAccessor(s.successProperty);
22702 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22704 var g = this.getJsonAccessor(s.id);
22705 this.getId = function(rec) {
22707 return (r === undefined || r === "") ? null : r;
22710 this.getId = function(){return null;};
22713 for(var jj = 0; jj < fl; jj++){
22715 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22716 this.ef[jj] = this.getJsonAccessor(map);
22720 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22721 if(s.totalProperty){
22722 var vt = parseInt(this.getTotal(o), 10);
22727 if(s.successProperty){
22728 var vs = this.getSuccess(o);
22729 if(vs === false || vs === 'false'){
22734 for(var i = 0; i < c; i++){
22737 var id = this.getId(n);
22738 for(var j = 0; j < fl; j++){
22740 var v = this.ef[j](n);
22742 Roo.log('missing convert for ' + f.name);
22746 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22748 var record = new Record(values, id);
22750 records[i] = record;
22756 totalRecords : totalRecords
22761 * Ext JS Library 1.1.1
22762 * Copyright(c) 2006-2007, Ext JS, LLC.
22764 * Originally Released Under LGPL - original licence link has changed is not relivant.
22767 * <script type="text/javascript">
22771 * @class Roo.data.XmlReader
22772 * @extends Roo.data.DataReader
22773 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22774 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22776 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22777 * header in the HTTP response must be set to "text/xml".</em>
22781 var RecordDef = Roo.data.Record.create([
22782 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22783 {name: 'occupation'} // This field will use "occupation" as the mapping.
22785 var myReader = new Roo.data.XmlReader({
22786 totalRecords: "results", // The element which contains the total dataset size (optional)
22787 record: "row", // The repeated element which contains row information
22788 id: "id" // The element within the row that provides an ID for the record (optional)
22792 * This would consume an XML file like this:
22796 <results>2</results>
22799 <name>Bill</name>
22800 <occupation>Gardener</occupation>
22804 <name>Ben</name>
22805 <occupation>Horticulturalist</occupation>
22809 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22810 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22811 * paged from the remote server.
22812 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22813 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22814 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22815 * a record identifier value.
22817 * Create a new XmlReader
22818 * @param {Object} meta Metadata configuration options
22819 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22820 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22821 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22823 Roo.data.XmlReader = function(meta, recordType){
22825 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22827 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22829 * This method is only used by a DataProxy which has retrieved data from a remote server.
22830 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22831 * to contain a method called 'responseXML' that returns an XML document object.
22832 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22833 * a cache of Roo.data.Records.
22835 read : function(response){
22836 var doc = response.responseXML;
22838 throw {message: "XmlReader.read: XML Document not available"};
22840 return this.readRecords(doc);
22844 * Create a data block containing Roo.data.Records from an XML document.
22845 * @param {Object} doc A parsed XML document.
22846 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22847 * a cache of Roo.data.Records.
22849 readRecords : function(doc){
22851 * After any data loads/reads, the raw XML Document is available for further custom processing.
22852 * @type XMLDocument
22854 this.xmlData = doc;
22855 var root = doc.documentElement || doc;
22856 var q = Roo.DomQuery;
22857 var recordType = this.recordType, fields = recordType.prototype.fields;
22858 var sid = this.meta.id;
22859 var totalRecords = 0, success = true;
22860 if(this.meta.totalRecords){
22861 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22864 if(this.meta.success){
22865 var sv = q.selectValue(this.meta.success, root, true);
22866 success = sv !== false && sv !== 'false';
22869 var ns = q.select(this.meta.record, root);
22870 for(var i = 0, len = ns.length; i < len; i++) {
22873 var id = sid ? q.selectValue(sid, n) : undefined;
22874 for(var j = 0, jlen = fields.length; j < jlen; j++){
22875 var f = fields.items[j];
22876 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22878 values[f.name] = v;
22880 var record = new recordType(values, id);
22882 records[records.length] = record;
22888 totalRecords : totalRecords || records.length
22893 * Ext JS Library 1.1.1
22894 * Copyright(c) 2006-2007, Ext JS, LLC.
22896 * Originally Released Under LGPL - original licence link has changed is not relivant.
22899 * <script type="text/javascript">
22903 * @class Roo.data.ArrayReader
22904 * @extends Roo.data.DataReader
22905 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22906 * Each element of that Array represents a row of data fields. The
22907 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22908 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22912 var RecordDef = Roo.data.Record.create([
22913 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22914 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22916 var myReader = new Roo.data.ArrayReader({
22917 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22921 * This would consume an Array like this:
22923 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22925 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22927 * Create a new JsonReader
22928 * @param {Object} meta Metadata configuration options.
22929 * @param {Object} recordType Either an Array of field definition objects
22930 * as specified to {@link Roo.data.Record#create},
22931 * or an {@link Roo.data.Record} object
22932 * created using {@link Roo.data.Record#create}.
22934 Roo.data.ArrayReader = function(meta, recordType){
22935 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22938 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22940 * Create a data block containing Roo.data.Records from an XML document.
22941 * @param {Object} o An Array of row objects which represents the dataset.
22942 * @return {Object} data A data block which is used by an Roo.data.Store object as
22943 * a cache of Roo.data.Records.
22945 readRecords : function(o){
22946 var sid = this.meta ? this.meta.id : null;
22947 var recordType = this.recordType, fields = recordType.prototype.fields;
22950 for(var i = 0; i < root.length; i++){
22953 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22954 for(var j = 0, jlen = fields.length; j < jlen; j++){
22955 var f = fields.items[j];
22956 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22957 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22959 values[f.name] = v;
22961 var record = new recordType(values, id);
22963 records[records.length] = record;
22967 totalRecords : records.length
22972 * Ext JS Library 1.1.1
22973 * Copyright(c) 2006-2007, Ext JS, LLC.
22975 * Originally Released Under LGPL - original licence link has changed is not relivant.
22978 * <script type="text/javascript">
22983 * @class Roo.data.Tree
22984 * @extends Roo.util.Observable
22985 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
22986 * in the tree have most standard DOM functionality.
22988 * @param {Node} root (optional) The root node
22990 Roo.data.Tree = function(root){
22991 this.nodeHash = {};
22993 * The root node for this tree
22998 this.setRootNode(root);
23003 * Fires when a new child node is appended to a node in this tree.
23004 * @param {Tree} tree The owner tree
23005 * @param {Node} parent The parent node
23006 * @param {Node} node The newly appended node
23007 * @param {Number} index The index of the newly appended node
23012 * Fires when a child node is removed from a node in this tree.
23013 * @param {Tree} tree The owner tree
23014 * @param {Node} parent The parent node
23015 * @param {Node} node The child node removed
23020 * Fires when a node is moved to a new location in the tree
23021 * @param {Tree} tree The owner tree
23022 * @param {Node} node The node moved
23023 * @param {Node} oldParent The old parent of this node
23024 * @param {Node} newParent The new parent of this node
23025 * @param {Number} index The index it was moved to
23030 * Fires when a new child node is inserted in a node in this tree.
23031 * @param {Tree} tree The owner tree
23032 * @param {Node} parent The parent node
23033 * @param {Node} node The child node inserted
23034 * @param {Node} refNode The child node the node was inserted before
23038 * @event beforeappend
23039 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
23040 * @param {Tree} tree The owner tree
23041 * @param {Node} parent The parent node
23042 * @param {Node} node The child node to be appended
23044 "beforeappend" : true,
23046 * @event beforeremove
23047 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
23048 * @param {Tree} tree The owner tree
23049 * @param {Node} parent The parent node
23050 * @param {Node} node The child node to be removed
23052 "beforeremove" : true,
23054 * @event beforemove
23055 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
23056 * @param {Tree} tree The owner tree
23057 * @param {Node} node The node being moved
23058 * @param {Node} oldParent The parent of the node
23059 * @param {Node} newParent The new parent the node is moving to
23060 * @param {Number} index The index it is being moved to
23062 "beforemove" : true,
23064 * @event beforeinsert
23065 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
23066 * @param {Tree} tree The owner tree
23067 * @param {Node} parent The parent node
23068 * @param {Node} node The child node to be inserted
23069 * @param {Node} refNode The child node the node is being inserted before
23071 "beforeinsert" : true
23074 Roo.data.Tree.superclass.constructor.call(this);
23077 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
23078 pathSeparator: "/",
23080 proxyNodeEvent : function(){
23081 return this.fireEvent.apply(this, arguments);
23085 * Returns the root node for this tree.
23088 getRootNode : function(){
23093 * Sets the root node for this tree.
23094 * @param {Node} node
23097 setRootNode : function(node){
23099 node.ownerTree = this;
23100 node.isRoot = true;
23101 this.registerNode(node);
23106 * Gets a node in this tree by its id.
23107 * @param {String} id
23110 getNodeById : function(id){
23111 return this.nodeHash[id];
23114 registerNode : function(node){
23115 this.nodeHash[node.id] = node;
23118 unregisterNode : function(node){
23119 delete this.nodeHash[node.id];
23122 toString : function(){
23123 return "[Tree"+(this.id?" "+this.id:"")+"]";
23128 * @class Roo.data.Node
23129 * @extends Roo.util.Observable
23130 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23131 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23133 * @param {Object} attributes The attributes/config for the node
23135 Roo.data.Node = function(attributes){
23137 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23140 this.attributes = attributes || {};
23141 this.leaf = this.attributes.leaf;
23143 * The node id. @type String
23145 this.id = this.attributes.id;
23147 this.id = Roo.id(null, "ynode-");
23148 this.attributes.id = this.id;
23153 * All child nodes of this node. @type Array
23155 this.childNodes = [];
23156 if(!this.childNodes.indexOf){ // indexOf is a must
23157 this.childNodes.indexOf = function(o){
23158 for(var i = 0, len = this.length; i < len; i++){
23167 * The parent node for this node. @type Node
23169 this.parentNode = null;
23171 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23173 this.firstChild = null;
23175 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23177 this.lastChild = null;
23179 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23181 this.previousSibling = null;
23183 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23185 this.nextSibling = null;
23190 * Fires when a new child node is appended
23191 * @param {Tree} tree The owner tree
23192 * @param {Node} this This node
23193 * @param {Node} node The newly appended node
23194 * @param {Number} index The index of the newly appended node
23199 * Fires when a child node is removed
23200 * @param {Tree} tree The owner tree
23201 * @param {Node} this This node
23202 * @param {Node} node The removed node
23207 * Fires when this node is moved to a new location in the tree
23208 * @param {Tree} tree The owner tree
23209 * @param {Node} this This node
23210 * @param {Node} oldParent The old parent of this node
23211 * @param {Node} newParent The new parent of this node
23212 * @param {Number} index The index it was moved to
23217 * Fires when a new child node is inserted.
23218 * @param {Tree} tree The owner tree
23219 * @param {Node} this This node
23220 * @param {Node} node The child node inserted
23221 * @param {Node} refNode The child node the node was inserted before
23225 * @event beforeappend
23226 * Fires before a new child is appended, return false to cancel the append.
23227 * @param {Tree} tree The owner tree
23228 * @param {Node} this This node
23229 * @param {Node} node The child node to be appended
23231 "beforeappend" : true,
23233 * @event beforeremove
23234 * Fires before a child is removed, return false to cancel the remove.
23235 * @param {Tree} tree The owner tree
23236 * @param {Node} this This node
23237 * @param {Node} node The child node to be removed
23239 "beforeremove" : true,
23241 * @event beforemove
23242 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23243 * @param {Tree} tree The owner tree
23244 * @param {Node} this This node
23245 * @param {Node} oldParent The parent of this node
23246 * @param {Node} newParent The new parent this node is moving to
23247 * @param {Number} index The index it is being moved to
23249 "beforemove" : true,
23251 * @event beforeinsert
23252 * Fires before a new child is inserted, return false to cancel the insert.
23253 * @param {Tree} tree The owner tree
23254 * @param {Node} this This node
23255 * @param {Node} node The child node to be inserted
23256 * @param {Node} refNode The child node the node is being inserted before
23258 "beforeinsert" : true
23260 this.listeners = this.attributes.listeners;
23261 Roo.data.Node.superclass.constructor.call(this);
23264 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23265 fireEvent : function(evtName){
23266 // first do standard event for this node
23267 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23270 // then bubble it up to the tree if the event wasn't cancelled
23271 var ot = this.getOwnerTree();
23273 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23281 * Returns true if this node is a leaf
23282 * @return {Boolean}
23284 isLeaf : function(){
23285 return this.leaf === true;
23289 setFirstChild : function(node){
23290 this.firstChild = node;
23294 setLastChild : function(node){
23295 this.lastChild = node;
23300 * Returns true if this node is the last child of its parent
23301 * @return {Boolean}
23303 isLast : function(){
23304 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23308 * Returns true if this node is the first child of its parent
23309 * @return {Boolean}
23311 isFirst : function(){
23312 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23315 hasChildNodes : function(){
23316 return !this.isLeaf() && this.childNodes.length > 0;
23320 * Insert node(s) as the last child node of this node.
23321 * @param {Node/Array} node The node or Array of nodes to append
23322 * @return {Node} The appended node if single append, or null if an array was passed
23324 appendChild : function(node){
23326 if(node instanceof Array){
23328 }else if(arguments.length > 1){
23331 // if passed an array or multiple args do them one by one
23333 for(var i = 0, len = multi.length; i < len; i++) {
23334 this.appendChild(multi[i]);
23337 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23340 var index = this.childNodes.length;
23341 var oldParent = node.parentNode;
23342 // it's a move, make sure we move it cleanly
23344 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23347 oldParent.removeChild(node);
23349 index = this.childNodes.length;
23351 this.setFirstChild(node);
23353 this.childNodes.push(node);
23354 node.parentNode = this;
23355 var ps = this.childNodes[index-1];
23357 node.previousSibling = ps;
23358 ps.nextSibling = node;
23360 node.previousSibling = null;
23362 node.nextSibling = null;
23363 this.setLastChild(node);
23364 node.setOwnerTree(this.getOwnerTree());
23365 this.fireEvent("append", this.ownerTree, this, node, index);
23367 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23374 * Removes a child node from this node.
23375 * @param {Node} node The node to remove
23376 * @return {Node} The removed node
23378 removeChild : function(node){
23379 var index = this.childNodes.indexOf(node);
23383 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23387 // remove it from childNodes collection
23388 this.childNodes.splice(index, 1);
23391 if(node.previousSibling){
23392 node.previousSibling.nextSibling = node.nextSibling;
23394 if(node.nextSibling){
23395 node.nextSibling.previousSibling = node.previousSibling;
23398 // update child refs
23399 if(this.firstChild == node){
23400 this.setFirstChild(node.nextSibling);
23402 if(this.lastChild == node){
23403 this.setLastChild(node.previousSibling);
23406 node.setOwnerTree(null);
23407 // clear any references from the node
23408 node.parentNode = null;
23409 node.previousSibling = null;
23410 node.nextSibling = null;
23411 this.fireEvent("remove", this.ownerTree, this, node);
23416 * Inserts the first node before the second node in this nodes childNodes collection.
23417 * @param {Node} node The node to insert
23418 * @param {Node} refNode The node to insert before (if null the node is appended)
23419 * @return {Node} The inserted node
23421 insertBefore : function(node, refNode){
23422 if(!refNode){ // like standard Dom, refNode can be null for append
23423 return this.appendChild(node);
23426 if(node == refNode){
23430 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23433 var index = this.childNodes.indexOf(refNode);
23434 var oldParent = node.parentNode;
23435 var refIndex = index;
23437 // when moving internally, indexes will change after remove
23438 if(oldParent == this && this.childNodes.indexOf(node) < index){
23442 // it's a move, make sure we move it cleanly
23444 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23447 oldParent.removeChild(node);
23450 this.setFirstChild(node);
23452 this.childNodes.splice(refIndex, 0, node);
23453 node.parentNode = this;
23454 var ps = this.childNodes[refIndex-1];
23456 node.previousSibling = ps;
23457 ps.nextSibling = node;
23459 node.previousSibling = null;
23461 node.nextSibling = refNode;
23462 refNode.previousSibling = node;
23463 node.setOwnerTree(this.getOwnerTree());
23464 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23466 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23472 * Returns the child node at the specified index.
23473 * @param {Number} index
23476 item : function(index){
23477 return this.childNodes[index];
23481 * Replaces one child node in this node with another.
23482 * @param {Node} newChild The replacement node
23483 * @param {Node} oldChild The node to replace
23484 * @return {Node} The replaced node
23486 replaceChild : function(newChild, oldChild){
23487 this.insertBefore(newChild, oldChild);
23488 this.removeChild(oldChild);
23493 * Returns the index of a child node
23494 * @param {Node} node
23495 * @return {Number} The index of the node or -1 if it was not found
23497 indexOf : function(child){
23498 return this.childNodes.indexOf(child);
23502 * Returns the tree this node is in.
23505 getOwnerTree : function(){
23506 // if it doesn't have one, look for one
23507 if(!this.ownerTree){
23511 this.ownerTree = p.ownerTree;
23517 return this.ownerTree;
23521 * Returns depth of this node (the root node has a depth of 0)
23524 getDepth : function(){
23527 while(p.parentNode){
23535 setOwnerTree : function(tree){
23536 // if it's move, we need to update everyone
23537 if(tree != this.ownerTree){
23538 if(this.ownerTree){
23539 this.ownerTree.unregisterNode(this);
23541 this.ownerTree = tree;
23542 var cs = this.childNodes;
23543 for(var i = 0, len = cs.length; i < len; i++) {
23544 cs[i].setOwnerTree(tree);
23547 tree.registerNode(this);
23553 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23554 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23555 * @return {String} The path
23557 getPath : function(attr){
23558 attr = attr || "id";
23559 var p = this.parentNode;
23560 var b = [this.attributes[attr]];
23562 b.unshift(p.attributes[attr]);
23565 var sep = this.getOwnerTree().pathSeparator;
23566 return sep + b.join(sep);
23570 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23571 * function call will be the scope provided or the current node. The arguments to the function
23572 * will be the args provided or the current node. If the function returns false at any point,
23573 * the bubble is stopped.
23574 * @param {Function} fn The function to call
23575 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23576 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23578 bubble : function(fn, scope, args){
23581 if(fn.call(scope || p, args || p) === false){
23589 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23590 * function call will be the scope provided or the current node. The arguments to the function
23591 * will be the args provided or the current node. If the function returns false at any point,
23592 * the cascade is stopped on that branch.
23593 * @param {Function} fn The function to call
23594 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23595 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23597 cascade : function(fn, scope, args){
23598 if(fn.call(scope || this, args || this) !== false){
23599 var cs = this.childNodes;
23600 for(var i = 0, len = cs.length; i < len; i++) {
23601 cs[i].cascade(fn, scope, args);
23607 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23608 * function call will be the scope provided or the current node. The arguments to the function
23609 * will be the args provided or the current node. If the function returns false at any point,
23610 * the iteration stops.
23611 * @param {Function} fn The function to call
23612 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23613 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23615 eachChild : function(fn, scope, args){
23616 var cs = this.childNodes;
23617 for(var i = 0, len = cs.length; i < len; i++) {
23618 if(fn.call(scope || this, args || cs[i]) === false){
23625 * Finds the first child that has the attribute with the specified value.
23626 * @param {String} attribute The attribute name
23627 * @param {Mixed} value The value to search for
23628 * @return {Node} The found child or null if none was found
23630 findChild : function(attribute, value){
23631 var cs = this.childNodes;
23632 for(var i = 0, len = cs.length; i < len; i++) {
23633 if(cs[i].attributes[attribute] == value){
23641 * Finds the first child by a custom function. The child matches if the function passed
23643 * @param {Function} fn
23644 * @param {Object} scope (optional)
23645 * @return {Node} The found child or null if none was found
23647 findChildBy : function(fn, scope){
23648 var cs = this.childNodes;
23649 for(var i = 0, len = cs.length; i < len; i++) {
23650 if(fn.call(scope||cs[i], cs[i]) === true){
23658 * Sorts this nodes children using the supplied sort function
23659 * @param {Function} fn
23660 * @param {Object} scope (optional)
23662 sort : function(fn, scope){
23663 var cs = this.childNodes;
23664 var len = cs.length;
23666 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23668 for(var i = 0; i < len; i++){
23670 n.previousSibling = cs[i-1];
23671 n.nextSibling = cs[i+1];
23673 this.setFirstChild(n);
23676 this.setLastChild(n);
23683 * Returns true if this node is an ancestor (at any point) of the passed node.
23684 * @param {Node} node
23685 * @return {Boolean}
23687 contains : function(node){
23688 return node.isAncestor(this);
23692 * Returns true if the passed node is an ancestor (at any point) of this node.
23693 * @param {Node} node
23694 * @return {Boolean}
23696 isAncestor : function(node){
23697 var p = this.parentNode;
23707 toString : function(){
23708 return "[Node"+(this.id?" "+this.id:"")+"]";
23712 * Ext JS Library 1.1.1
23713 * Copyright(c) 2006-2007, Ext JS, LLC.
23715 * Originally Released Under LGPL - original licence link has changed is not relivant.
23718 * <script type="text/javascript">
23723 * @extends Roo.Element
23724 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23725 * automatic maintaining of shadow/shim positions.
23726 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23727 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23728 * you can pass a string with a CSS class name. False turns off the shadow.
23729 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23730 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23731 * @cfg {String} cls CSS class to add to the element
23732 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23733 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23735 * @param {Object} config An object with config options.
23736 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23739 Roo.Layer = function(config, existingEl){
23740 config = config || {};
23741 var dh = Roo.DomHelper;
23742 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23744 this.dom = Roo.getDom(existingEl);
23747 var o = config.dh || {tag: "div", cls: "x-layer"};
23748 this.dom = dh.append(pel, o);
23751 this.addClass(config.cls);
23753 this.constrain = config.constrain !== false;
23754 this.visibilityMode = Roo.Element.VISIBILITY;
23756 this.id = this.dom.id = config.id;
23758 this.id = Roo.id(this.dom);
23760 this.zindex = config.zindex || this.getZIndex();
23761 this.position("absolute", this.zindex);
23763 this.shadowOffset = config.shadowOffset || 4;
23764 this.shadow = new Roo.Shadow({
23765 offset : this.shadowOffset,
23766 mode : config.shadow
23769 this.shadowOffset = 0;
23771 this.useShim = config.shim !== false && Roo.useShims;
23772 this.useDisplay = config.useDisplay;
23776 var supr = Roo.Element.prototype;
23778 // shims are shared among layer to keep from having 100 iframes
23781 Roo.extend(Roo.Layer, Roo.Element, {
23783 getZIndex : function(){
23784 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23787 getShim : function(){
23794 var shim = shims.shift();
23796 shim = this.createShim();
23797 shim.enableDisplayMode('block');
23798 shim.dom.style.display = 'none';
23799 shim.dom.style.visibility = 'visible';
23801 var pn = this.dom.parentNode;
23802 if(shim.dom.parentNode != pn){
23803 pn.insertBefore(shim.dom, this.dom);
23805 shim.setStyle('z-index', this.getZIndex()-2);
23810 hideShim : function(){
23812 this.shim.setDisplayed(false);
23813 shims.push(this.shim);
23818 disableShadow : function(){
23820 this.shadowDisabled = true;
23821 this.shadow.hide();
23822 this.lastShadowOffset = this.shadowOffset;
23823 this.shadowOffset = 0;
23827 enableShadow : function(show){
23829 this.shadowDisabled = false;
23830 this.shadowOffset = this.lastShadowOffset;
23831 delete this.lastShadowOffset;
23839 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23840 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23841 sync : function(doShow){
23842 var sw = this.shadow;
23843 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23844 var sh = this.getShim();
23846 var w = this.getWidth(),
23847 h = this.getHeight();
23849 var l = this.getLeft(true),
23850 t = this.getTop(true);
23852 if(sw && !this.shadowDisabled){
23853 if(doShow && !sw.isVisible()){
23856 sw.realign(l, t, w, h);
23862 // fit the shim behind the shadow, so it is shimmed too
23863 var a = sw.adjusts, s = sh.dom.style;
23864 s.left = (Math.min(l, l+a.l))+"px";
23865 s.top = (Math.min(t, t+a.t))+"px";
23866 s.width = (w+a.w)+"px";
23867 s.height = (h+a.h)+"px";
23874 sh.setLeftTop(l, t);
23881 destroy : function(){
23884 this.shadow.hide();
23886 this.removeAllListeners();
23887 var pn = this.dom.parentNode;
23889 pn.removeChild(this.dom);
23891 Roo.Element.uncache(this.id);
23894 remove : function(){
23899 beginUpdate : function(){
23900 this.updating = true;
23904 endUpdate : function(){
23905 this.updating = false;
23910 hideUnders : function(negOffset){
23912 this.shadow.hide();
23918 constrainXY : function(){
23919 if(this.constrain){
23920 var vw = Roo.lib.Dom.getViewWidth(),
23921 vh = Roo.lib.Dom.getViewHeight();
23922 var s = Roo.get(document).getScroll();
23924 var xy = this.getXY();
23925 var x = xy[0], y = xy[1];
23926 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23927 // only move it if it needs it
23929 // first validate right/bottom
23930 if((x + w) > vw+s.left){
23931 x = vw - w - this.shadowOffset;
23934 if((y + h) > vh+s.top){
23935 y = vh - h - this.shadowOffset;
23938 // then make sure top/left isn't negative
23949 var ay = this.avoidY;
23950 if(y <= ay && (y+h) >= ay){
23956 supr.setXY.call(this, xy);
23962 isVisible : function(){
23963 return this.visible;
23967 showAction : function(){
23968 this.visible = true; // track visibility to prevent getStyle calls
23969 if(this.useDisplay === true){
23970 this.setDisplayed("");
23971 }else if(this.lastXY){
23972 supr.setXY.call(this, this.lastXY);
23973 }else if(this.lastLT){
23974 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23979 hideAction : function(){
23980 this.visible = false;
23981 if(this.useDisplay === true){
23982 this.setDisplayed(false);
23984 this.setLeftTop(-10000,-10000);
23988 // overridden Element method
23989 setVisible : function(v, a, d, c, e){
23994 var cb = function(){
23999 }.createDelegate(this);
24000 supr.setVisible.call(this, true, true, d, cb, e);
24003 this.hideUnders(true);
24012 }.createDelegate(this);
24014 supr.setVisible.call(this, v, a, d, cb, e);
24023 storeXY : function(xy){
24024 delete this.lastLT;
24028 storeLeftTop : function(left, top){
24029 delete this.lastXY;
24030 this.lastLT = [left, top];
24034 beforeFx : function(){
24035 this.beforeAction();
24036 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
24040 afterFx : function(){
24041 Roo.Layer.superclass.afterFx.apply(this, arguments);
24042 this.sync(this.isVisible());
24046 beforeAction : function(){
24047 if(!this.updating && this.shadow){
24048 this.shadow.hide();
24052 // overridden Element method
24053 setLeft : function(left){
24054 this.storeLeftTop(left, this.getTop(true));
24055 supr.setLeft.apply(this, arguments);
24059 setTop : function(top){
24060 this.storeLeftTop(this.getLeft(true), top);
24061 supr.setTop.apply(this, arguments);
24065 setLeftTop : function(left, top){
24066 this.storeLeftTop(left, top);
24067 supr.setLeftTop.apply(this, arguments);
24071 setXY : function(xy, a, d, c, e){
24073 this.beforeAction();
24075 var cb = this.createCB(c);
24076 supr.setXY.call(this, xy, a, d, cb, e);
24083 createCB : function(c){
24094 // overridden Element method
24095 setX : function(x, a, d, c, e){
24096 this.setXY([x, this.getY()], a, d, c, e);
24099 // overridden Element method
24100 setY : function(y, a, d, c, e){
24101 this.setXY([this.getX(), y], a, d, c, e);
24104 // overridden Element method
24105 setSize : function(w, h, a, d, c, e){
24106 this.beforeAction();
24107 var cb = this.createCB(c);
24108 supr.setSize.call(this, w, h, a, d, cb, e);
24114 // overridden Element method
24115 setWidth : function(w, a, d, c, e){
24116 this.beforeAction();
24117 var cb = this.createCB(c);
24118 supr.setWidth.call(this, w, a, d, cb, e);
24124 // overridden Element method
24125 setHeight : function(h, a, d, c, e){
24126 this.beforeAction();
24127 var cb = this.createCB(c);
24128 supr.setHeight.call(this, h, a, d, cb, e);
24134 // overridden Element method
24135 setBounds : function(x, y, w, h, a, d, c, e){
24136 this.beforeAction();
24137 var cb = this.createCB(c);
24139 this.storeXY([x, y]);
24140 supr.setXY.call(this, [x, y]);
24141 supr.setSize.call(this, w, h, a, d, cb, e);
24144 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24150 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24151 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24152 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24153 * @param {Number} zindex The new z-index to set
24154 * @return {this} The Layer
24156 setZIndex : function(zindex){
24157 this.zindex = zindex;
24158 this.setStyle("z-index", zindex + 2);
24160 this.shadow.setZIndex(zindex + 1);
24163 this.shim.setStyle("z-index", zindex);
24169 * Ext JS Library 1.1.1
24170 * Copyright(c) 2006-2007, Ext JS, LLC.
24172 * Originally Released Under LGPL - original licence link has changed is not relivant.
24175 * <script type="text/javascript">
24180 * @class Roo.Shadow
24181 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24182 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24183 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24185 * Create a new Shadow
24186 * @param {Object} config The config object
24188 Roo.Shadow = function(config){
24189 Roo.apply(this, config);
24190 if(typeof this.mode != "string"){
24191 this.mode = this.defaultMode;
24193 var o = this.offset, a = {h: 0};
24194 var rad = Math.floor(this.offset/2);
24195 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24201 a.l -= this.offset + rad;
24202 a.t -= this.offset + rad;
24213 a.l -= (this.offset - rad);
24214 a.t -= this.offset + rad;
24216 a.w -= (this.offset - rad)*2;
24227 a.l -= (this.offset - rad);
24228 a.t -= (this.offset - rad);
24230 a.w -= (this.offset + rad + 1);
24231 a.h -= (this.offset + rad);
24240 Roo.Shadow.prototype = {
24242 * @cfg {String} mode
24243 * The shadow display mode. Supports the following options:<br />
24244 * sides: Shadow displays on both sides and bottom only<br />
24245 * frame: Shadow displays equally on all four sides<br />
24246 * drop: Traditional bottom-right drop shadow (default)
24249 * @cfg {String} offset
24250 * The number of pixels to offset the shadow from the element (defaults to 4)
24255 defaultMode: "drop",
24258 * Displays the shadow under the target element
24259 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24261 show : function(target){
24262 target = Roo.get(target);
24264 this.el = Roo.Shadow.Pool.pull();
24265 if(this.el.dom.nextSibling != target.dom){
24266 this.el.insertBefore(target);
24269 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24271 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24274 target.getLeft(true),
24275 target.getTop(true),
24279 this.el.dom.style.display = "block";
24283 * Returns true if the shadow is visible, else false
24285 isVisible : function(){
24286 return this.el ? true : false;
24290 * Direct alignment when values are already available. Show must be called at least once before
24291 * calling this method to ensure it is initialized.
24292 * @param {Number} left The target element left position
24293 * @param {Number} top The target element top position
24294 * @param {Number} width The target element width
24295 * @param {Number} height The target element height
24297 realign : function(l, t, w, h){
24301 var a = this.adjusts, d = this.el.dom, s = d.style;
24303 s.left = (l+a.l)+"px";
24304 s.top = (t+a.t)+"px";
24305 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24307 if(s.width != sws || s.height != shs){
24311 var cn = d.childNodes;
24312 var sww = Math.max(0, (sw-12))+"px";
24313 cn[0].childNodes[1].style.width = sww;
24314 cn[1].childNodes[1].style.width = sww;
24315 cn[2].childNodes[1].style.width = sww;
24316 cn[1].style.height = Math.max(0, (sh-12))+"px";
24322 * Hides this shadow
24326 this.el.dom.style.display = "none";
24327 Roo.Shadow.Pool.push(this.el);
24333 * Adjust the z-index of this shadow
24334 * @param {Number} zindex The new z-index
24336 setZIndex : function(z){
24339 this.el.setStyle("z-index", z);
24344 // Private utility class that manages the internal Shadow cache
24345 Roo.Shadow.Pool = function(){
24347 var markup = Roo.isIE ?
24348 '<div class="x-ie-shadow"></div>' :
24349 '<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>';
24352 var sh = p.shift();
24354 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24355 sh.autoBoxAdjust = false;
24360 push : function(sh){
24366 * Ext JS Library 1.1.1
24367 * Copyright(c) 2006-2007, Ext JS, LLC.
24369 * Originally Released Under LGPL - original licence link has changed is not relivant.
24372 * <script type="text/javascript">
24377 * @class Roo.SplitBar
24378 * @extends Roo.util.Observable
24379 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24383 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24384 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24385 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24386 split.minSize = 100;
24387 split.maxSize = 600;
24388 split.animate = true;
24389 split.on('moved', splitterMoved);
24392 * Create a new SplitBar
24393 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24394 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24395 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24396 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24397 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24398 position of the SplitBar).
24400 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24403 this.el = Roo.get(dragElement, true);
24404 this.el.dom.unselectable = "on";
24406 this.resizingEl = Roo.get(resizingElement, true);
24410 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24411 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24414 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24417 * The minimum size of the resizing element. (Defaults to 0)
24423 * The maximum size of the resizing element. (Defaults to 2000)
24426 this.maxSize = 2000;
24429 * Whether to animate the transition to the new size
24432 this.animate = false;
24435 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24438 this.useShim = false;
24443 if(!existingProxy){
24445 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24447 this.proxy = Roo.get(existingProxy).dom;
24450 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24453 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24456 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24459 this.dragSpecs = {};
24462 * @private The adapter to use to positon and resize elements
24464 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24465 this.adapter.init(this);
24467 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24469 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24470 this.el.addClass("x-splitbar-h");
24473 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24474 this.el.addClass("x-splitbar-v");
24480 * Fires when the splitter is moved (alias for {@link #event-moved})
24481 * @param {Roo.SplitBar} this
24482 * @param {Number} newSize the new width or height
24487 * Fires when the splitter is moved
24488 * @param {Roo.SplitBar} this
24489 * @param {Number} newSize the new width or height
24493 * @event beforeresize
24494 * Fires before the splitter is dragged
24495 * @param {Roo.SplitBar} this
24497 "beforeresize" : true,
24499 "beforeapply" : true
24502 Roo.util.Observable.call(this);
24505 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24506 onStartProxyDrag : function(x, y){
24507 this.fireEvent("beforeresize", this);
24509 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24511 o.enableDisplayMode("block");
24512 // all splitbars share the same overlay
24513 Roo.SplitBar.prototype.overlay = o;
24515 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24516 this.overlay.show();
24517 Roo.get(this.proxy).setDisplayed("block");
24518 var size = this.adapter.getElementSize(this);
24519 this.activeMinSize = this.getMinimumSize();;
24520 this.activeMaxSize = this.getMaximumSize();;
24521 var c1 = size - this.activeMinSize;
24522 var c2 = Math.max(this.activeMaxSize - size, 0);
24523 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24524 this.dd.resetConstraints();
24525 this.dd.setXConstraint(
24526 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24527 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24529 this.dd.setYConstraint(0, 0);
24531 this.dd.resetConstraints();
24532 this.dd.setXConstraint(0, 0);
24533 this.dd.setYConstraint(
24534 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24535 this.placement == Roo.SplitBar.TOP ? c2 : c1
24538 this.dragSpecs.startSize = size;
24539 this.dragSpecs.startPoint = [x, y];
24540 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24544 * @private Called after the drag operation by the DDProxy
24546 onEndProxyDrag : function(e){
24547 Roo.get(this.proxy).setDisplayed(false);
24548 var endPoint = Roo.lib.Event.getXY(e);
24550 this.overlay.hide();
24553 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24554 newSize = this.dragSpecs.startSize +
24555 (this.placement == Roo.SplitBar.LEFT ?
24556 endPoint[0] - this.dragSpecs.startPoint[0] :
24557 this.dragSpecs.startPoint[0] - endPoint[0]
24560 newSize = this.dragSpecs.startSize +
24561 (this.placement == Roo.SplitBar.TOP ?
24562 endPoint[1] - this.dragSpecs.startPoint[1] :
24563 this.dragSpecs.startPoint[1] - endPoint[1]
24566 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24567 if(newSize != this.dragSpecs.startSize){
24568 if(this.fireEvent('beforeapply', this, newSize) !== false){
24569 this.adapter.setElementSize(this, newSize);
24570 this.fireEvent("moved", this, newSize);
24571 this.fireEvent("resize", this, newSize);
24577 * Get the adapter this SplitBar uses
24578 * @return The adapter object
24580 getAdapter : function(){
24581 return this.adapter;
24585 * Set the adapter this SplitBar uses
24586 * @param {Object} adapter A SplitBar adapter object
24588 setAdapter : function(adapter){
24589 this.adapter = adapter;
24590 this.adapter.init(this);
24594 * Gets the minimum size for the resizing element
24595 * @return {Number} The minimum size
24597 getMinimumSize : function(){
24598 return this.minSize;
24602 * Sets the minimum size for the resizing element
24603 * @param {Number} minSize The minimum size
24605 setMinimumSize : function(minSize){
24606 this.minSize = minSize;
24610 * Gets the maximum size for the resizing element
24611 * @return {Number} The maximum size
24613 getMaximumSize : function(){
24614 return this.maxSize;
24618 * Sets the maximum size for the resizing element
24619 * @param {Number} maxSize The maximum size
24621 setMaximumSize : function(maxSize){
24622 this.maxSize = maxSize;
24626 * Sets the initialize size for the resizing element
24627 * @param {Number} size The initial size
24629 setCurrentSize : function(size){
24630 var oldAnimate = this.animate;
24631 this.animate = false;
24632 this.adapter.setElementSize(this, size);
24633 this.animate = oldAnimate;
24637 * Destroy this splitbar.
24638 * @param {Boolean} removeEl True to remove the element
24640 destroy : function(removeEl){
24642 this.shim.remove();
24645 this.proxy.parentNode.removeChild(this.proxy);
24653 * @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.
24655 Roo.SplitBar.createProxy = function(dir){
24656 var proxy = new Roo.Element(document.createElement("div"));
24657 proxy.unselectable();
24658 var cls = 'x-splitbar-proxy';
24659 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24660 document.body.appendChild(proxy.dom);
24665 * @class Roo.SplitBar.BasicLayoutAdapter
24666 * Default Adapter. It assumes the splitter and resizing element are not positioned
24667 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24669 Roo.SplitBar.BasicLayoutAdapter = function(){
24672 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24673 // do nothing for now
24674 init : function(s){
24678 * Called before drag operations to get the current size of the resizing element.
24679 * @param {Roo.SplitBar} s The SplitBar using this adapter
24681 getElementSize : function(s){
24682 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24683 return s.resizingEl.getWidth();
24685 return s.resizingEl.getHeight();
24690 * Called after drag operations to set the size of the resizing element.
24691 * @param {Roo.SplitBar} s The SplitBar using this adapter
24692 * @param {Number} newSize The new size to set
24693 * @param {Function} onComplete A function to be invoked when resizing is complete
24695 setElementSize : function(s, newSize, onComplete){
24696 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24698 s.resizingEl.setWidth(newSize);
24700 onComplete(s, newSize);
24703 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24708 s.resizingEl.setHeight(newSize);
24710 onComplete(s, newSize);
24713 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24720 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24721 * @extends Roo.SplitBar.BasicLayoutAdapter
24722 * Adapter that moves the splitter element to align with the resized sizing element.
24723 * Used with an absolute positioned SplitBar.
24724 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24725 * document.body, make sure you assign an id to the body element.
24727 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24728 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24729 this.container = Roo.get(container);
24732 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24733 init : function(s){
24734 this.basic.init(s);
24737 getElementSize : function(s){
24738 return this.basic.getElementSize(s);
24741 setElementSize : function(s, newSize, onComplete){
24742 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24745 moveSplitter : function(s){
24746 var yes = Roo.SplitBar;
24747 switch(s.placement){
24749 s.el.setX(s.resizingEl.getRight());
24752 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24755 s.el.setY(s.resizingEl.getBottom());
24758 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24765 * Orientation constant - Create a vertical SplitBar
24769 Roo.SplitBar.VERTICAL = 1;
24772 * Orientation constant - Create a horizontal SplitBar
24776 Roo.SplitBar.HORIZONTAL = 2;
24779 * Placement constant - The resizing element is to the left of the splitter element
24783 Roo.SplitBar.LEFT = 1;
24786 * Placement constant - The resizing element is to the right of the splitter element
24790 Roo.SplitBar.RIGHT = 2;
24793 * Placement constant - The resizing element is positioned above the splitter element
24797 Roo.SplitBar.TOP = 3;
24800 * Placement constant - The resizing element is positioned under splitter element
24804 Roo.SplitBar.BOTTOM = 4;
24807 * Ext JS Library 1.1.1
24808 * Copyright(c) 2006-2007, Ext JS, LLC.
24810 * Originally Released Under LGPL - original licence link has changed is not relivant.
24813 * <script type="text/javascript">
24818 * @extends Roo.util.Observable
24819 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24820 * This class also supports single and multi selection modes. <br>
24821 * Create a data model bound view:
24823 var store = new Roo.data.Store(...);
24825 var view = new Roo.View({
24827 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24829 singleSelect: true,
24830 selectedClass: "ydataview-selected",
24834 // listen for node click?
24835 view.on("click", function(vw, index, node, e){
24836 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24840 dataModel.load("foobar.xml");
24842 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24844 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24845 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24847 * Note: old style constructor is still suported (container, template, config)
24850 * Create a new View
24851 * @param {Object} config The config object
24854 Roo.View = function(config, depreciated_tpl, depreciated_config){
24856 this.parent = false;
24858 if (typeof(depreciated_tpl) == 'undefined') {
24859 // new way.. - universal constructor.
24860 Roo.apply(this, config);
24861 this.el = Roo.get(this.el);
24864 this.el = Roo.get(config);
24865 this.tpl = depreciated_tpl;
24866 Roo.apply(this, depreciated_config);
24868 this.wrapEl = this.el.wrap().wrap();
24869 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24872 if(typeof(this.tpl) == "string"){
24873 this.tpl = new Roo.Template(this.tpl);
24875 // support xtype ctors..
24876 this.tpl = new Roo.factory(this.tpl, Roo);
24880 this.tpl.compile();
24885 * @event beforeclick
24886 * Fires before a click is processed. Returns false to cancel the default action.
24887 * @param {Roo.View} this
24888 * @param {Number} index The index of the target node
24889 * @param {HTMLElement} node The target node
24890 * @param {Roo.EventObject} e The raw event object
24892 "beforeclick" : true,
24895 * Fires when a template node is clicked.
24896 * @param {Roo.View} this
24897 * @param {Number} index The index of the target node
24898 * @param {HTMLElement} node The target node
24899 * @param {Roo.EventObject} e The raw event object
24904 * Fires when a template node is double clicked.
24905 * @param {Roo.View} this
24906 * @param {Number} index The index of the target node
24907 * @param {HTMLElement} node The target node
24908 * @param {Roo.EventObject} e The raw event object
24912 * @event contextmenu
24913 * Fires when a template node is right clicked.
24914 * @param {Roo.View} this
24915 * @param {Number} index The index of the target node
24916 * @param {HTMLElement} node The target node
24917 * @param {Roo.EventObject} e The raw event object
24919 "contextmenu" : true,
24921 * @event selectionchange
24922 * Fires when the selected nodes change.
24923 * @param {Roo.View} this
24924 * @param {Array} selections Array of the selected nodes
24926 "selectionchange" : true,
24929 * @event beforeselect
24930 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24931 * @param {Roo.View} this
24932 * @param {HTMLElement} node The node to be selected
24933 * @param {Array} selections Array of currently selected nodes
24935 "beforeselect" : true,
24937 * @event preparedata
24938 * Fires on every row to render, to allow you to change the data.
24939 * @param {Roo.View} this
24940 * @param {Object} data to be rendered (change this)
24942 "preparedata" : true
24950 "click": this.onClick,
24951 "dblclick": this.onDblClick,
24952 "contextmenu": this.onContextMenu,
24956 this.selections = [];
24958 this.cmp = new Roo.CompositeElementLite([]);
24960 this.store = Roo.factory(this.store, Roo.data);
24961 this.setStore(this.store, true);
24964 if ( this.footer && this.footer.xtype) {
24966 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24968 this.footer.dataSource = this.store
24969 this.footer.container = fctr;
24970 this.footer = Roo.factory(this.footer, Roo);
24971 fctr.insertFirst(this.el);
24973 // this is a bit insane - as the paging toolbar seems to detach the el..
24974 // dom.parentNode.parentNode.parentNode
24975 // they get detached?
24979 Roo.View.superclass.constructor.call(this);
24984 Roo.extend(Roo.View, Roo.util.Observable, {
24987 * @cfg {Roo.data.Store} store Data store to load data from.
24992 * @cfg {String|Roo.Element} el The container element.
24997 * @cfg {String|Roo.Template} tpl The template used by this View
25001 * @cfg {String} dataName the named area of the template to use as the data area
25002 * Works with domtemplates roo-name="name"
25006 * @cfg {String} selectedClass The css class to add to selected nodes
25008 selectedClass : "x-view-selected",
25010 * @cfg {String} emptyText The empty text to show when nothing is loaded.
25015 * @cfg {String} text to display on mask (default Loading)
25019 * @cfg {Boolean} multiSelect Allow multiple selection
25021 multiSelect : false,
25023 * @cfg {Boolean} singleSelect Allow single selection
25025 singleSelect: false,
25028 * @cfg {Boolean} toggleSelect - selecting
25030 toggleSelect : false,
25033 * @cfg {Boolean} tickable - selecting
25038 * Returns the element this view is bound to.
25039 * @return {Roo.Element}
25041 getEl : function(){
25042 return this.wrapEl;
25048 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25050 refresh : function(){
25051 Roo.log('refresh');
25054 // if we are using something like 'domtemplate', then
25055 // the what gets used is:
25056 // t.applySubtemplate(NAME, data, wrapping data..)
25057 // the outer template then get' applied with
25058 // the store 'extra data'
25059 // and the body get's added to the
25060 // roo-name="data" node?
25061 // <span class='roo-tpl-{name}'></span> ?????
25065 this.clearSelections();
25066 this.el.update("");
25068 var records = this.store.getRange();
25069 if(records.length < 1) {
25071 // is this valid?? = should it render a template??
25073 this.el.update(this.emptyText);
25077 if (this.dataName) {
25078 this.el.update(t.apply(this.store.meta)); //????
25079 el = this.el.child('.roo-tpl-' + this.dataName);
25082 for(var i = 0, len = records.length; i < len; i++){
25083 var data = this.prepareData(records[i].data, i, records[i]);
25084 this.fireEvent("preparedata", this, data, i, records[i]);
25086 var d = Roo.apply({}, data);
25089 Roo.apply(d, {'roo-id' : Roo.id()});
25093 Roo.each(this.parent.item, function(item){
25094 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
25097 Roo.apply(d, {'roo-data-checked' : 'checked'});
25101 html[html.length] = Roo.util.Format.trim(
25103 t.applySubtemplate(this.dataName, d, this.store.meta) :
25110 el.update(html.join(""));
25111 this.nodes = el.dom.childNodes;
25112 this.updateIndexes(0);
25117 * Function to override to reformat the data that is sent to
25118 * the template for each node.
25119 * DEPRICATED - use the preparedata event handler.
25120 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25121 * a JSON object for an UpdateManager bound view).
25123 prepareData : function(data, index, record)
25125 this.fireEvent("preparedata", this, data, index, record);
25129 onUpdate : function(ds, record){
25130 Roo.log('on update');
25131 this.clearSelections();
25132 var index = this.store.indexOf(record);
25133 var n = this.nodes[index];
25134 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25135 n.parentNode.removeChild(n);
25136 this.updateIndexes(index, index);
25142 onAdd : function(ds, records, index)
25144 Roo.log(['on Add', ds, records, index] );
25145 this.clearSelections();
25146 if(this.nodes.length == 0){
25150 var n = this.nodes[index];
25151 for(var i = 0, len = records.length; i < len; i++){
25152 var d = this.prepareData(records[i].data, i, records[i]);
25154 this.tpl.insertBefore(n, d);
25157 this.tpl.append(this.el, d);
25160 this.updateIndexes(index);
25163 onRemove : function(ds, record, index){
25164 Roo.log('onRemove');
25165 this.clearSelections();
25166 var el = this.dataName ?
25167 this.el.child('.roo-tpl-' + this.dataName) :
25170 el.dom.removeChild(this.nodes[index]);
25171 this.updateIndexes(index);
25175 * Refresh an individual node.
25176 * @param {Number} index
25178 refreshNode : function(index){
25179 this.onUpdate(this.store, this.store.getAt(index));
25182 updateIndexes : function(startIndex, endIndex){
25183 var ns = this.nodes;
25184 startIndex = startIndex || 0;
25185 endIndex = endIndex || ns.length - 1;
25186 for(var i = startIndex; i <= endIndex; i++){
25187 ns[i].nodeIndex = i;
25192 * Changes the data store this view uses and refresh the view.
25193 * @param {Store} store
25195 setStore : function(store, initial){
25196 if(!initial && this.store){
25197 this.store.un("datachanged", this.refresh);
25198 this.store.un("add", this.onAdd);
25199 this.store.un("remove", this.onRemove);
25200 this.store.un("update", this.onUpdate);
25201 this.store.un("clear", this.refresh);
25202 this.store.un("beforeload", this.onBeforeLoad);
25203 this.store.un("load", this.onLoad);
25204 this.store.un("loadexception", this.onLoad);
25208 store.on("datachanged", this.refresh, this);
25209 store.on("add", this.onAdd, this);
25210 store.on("remove", this.onRemove, this);
25211 store.on("update", this.onUpdate, this);
25212 store.on("clear", this.refresh, this);
25213 store.on("beforeload", this.onBeforeLoad, this);
25214 store.on("load", this.onLoad, this);
25215 store.on("loadexception", this.onLoad, this);
25223 * onbeforeLoad - masks the loading area.
25226 onBeforeLoad : function(store,opts)
25228 Roo.log('onBeforeLoad');
25230 this.el.update("");
25232 this.el.mask(this.mask ? this.mask : "Loading" );
25234 onLoad : function ()
25241 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25242 * @param {HTMLElement} node
25243 * @return {HTMLElement} The template node
25245 findItemFromChild : function(node){
25246 var el = this.dataName ?
25247 this.el.child('.roo-tpl-' + this.dataName,true) :
25250 if(!node || node.parentNode == el){
25253 var p = node.parentNode;
25254 while(p && p != el){
25255 if(p.parentNode == el){
25264 onClick : function(e){
25265 var item = this.findItemFromChild(e.getTarget());
25267 var index = this.indexOf(item);
25268 if(this.onItemClick(item, index, e) !== false){
25269 this.fireEvent("click", this, index, item, e);
25272 this.clearSelections();
25277 onContextMenu : function(e){
25278 var item = this.findItemFromChild(e.getTarget());
25280 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25285 onDblClick : function(e){
25286 var item = this.findItemFromChild(e.getTarget());
25288 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25292 onItemClick : function(item, index, e)
25294 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25297 if (this.toggleSelect) {
25298 var m = this.isSelected(item) ? 'unselect' : 'select';
25301 _t[m](item, true, false);
25304 if(this.multiSelect || this.singleSelect){
25305 if(this.multiSelect && e.shiftKey && this.lastSelection){
25306 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25308 this.select(item, this.multiSelect && e.ctrlKey);
25309 this.lastSelection = item;
25312 if(!this.tickable){
25313 e.preventDefault();
25321 * Get the number of selected nodes.
25324 getSelectionCount : function(){
25325 return this.selections.length;
25329 * Get the currently selected nodes.
25330 * @return {Array} An array of HTMLElements
25332 getSelectedNodes : function(){
25333 return this.selections;
25337 * Get the indexes of the selected nodes.
25340 getSelectedIndexes : function(){
25341 var indexes = [], s = this.selections;
25342 for(var i = 0, len = s.length; i < len; i++){
25343 indexes.push(s[i].nodeIndex);
25349 * Clear all selections
25350 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25352 clearSelections : function(suppressEvent){
25353 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25354 this.cmp.elements = this.selections;
25355 this.cmp.removeClass(this.selectedClass);
25356 this.selections = [];
25357 if(!suppressEvent){
25358 this.fireEvent("selectionchange", this, this.selections);
25364 * Returns true if the passed node is selected
25365 * @param {HTMLElement/Number} node The node or node index
25366 * @return {Boolean}
25368 isSelected : function(node){
25369 var s = this.selections;
25373 node = this.getNode(node);
25374 return s.indexOf(node) !== -1;
25379 * @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
25380 * @param {Boolean} keepExisting (optional) true to keep existing selections
25381 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25383 select : function(nodeInfo, keepExisting, suppressEvent){
25384 if(nodeInfo instanceof Array){
25386 this.clearSelections(true);
25388 for(var i = 0, len = nodeInfo.length; i < len; i++){
25389 this.select(nodeInfo[i], true, true);
25393 var node = this.getNode(nodeInfo);
25394 if(!node || this.isSelected(node)){
25395 return; // already selected.
25398 this.clearSelections(true);
25400 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25401 Roo.fly(node).addClass(this.selectedClass);
25402 this.selections.push(node);
25403 if(!suppressEvent){
25404 this.fireEvent("selectionchange", this, this.selections);
25412 * @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
25413 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25414 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25416 unselect : function(nodeInfo, keepExisting, suppressEvent)
25418 if(nodeInfo instanceof Array){
25419 Roo.each(this.selections, function(s) {
25420 this.unselect(s, nodeInfo);
25424 var node = this.getNode(nodeInfo);
25425 if(!node || !this.isSelected(node)){
25426 Roo.log("not selected");
25427 return; // not selected.
25431 Roo.each(this.selections, function(s) {
25433 Roo.fly(node).removeClass(this.selectedClass);
25440 this.selections= ns;
25441 this.fireEvent("selectionchange", this, this.selections);
25445 * Gets a template node.
25446 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25447 * @return {HTMLElement} The node or null if it wasn't found
25449 getNode : function(nodeInfo){
25450 if(typeof nodeInfo == "string"){
25451 return document.getElementById(nodeInfo);
25452 }else if(typeof nodeInfo == "number"){
25453 return this.nodes[nodeInfo];
25459 * Gets a range template nodes.
25460 * @param {Number} startIndex
25461 * @param {Number} endIndex
25462 * @return {Array} An array of nodes
25464 getNodes : function(start, end){
25465 var ns = this.nodes;
25466 start = start || 0;
25467 end = typeof end == "undefined" ? ns.length - 1 : end;
25470 for(var i = start; i <= end; i++){
25474 for(var i = start; i >= end; i--){
25482 * Finds the index of the passed node
25483 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25484 * @return {Number} The index of the node or -1
25486 indexOf : function(node){
25487 node = this.getNode(node);
25488 if(typeof node.nodeIndex == "number"){
25489 return node.nodeIndex;
25491 var ns = this.nodes;
25492 for(var i = 0, len = ns.length; i < len; i++){
25502 * Ext JS Library 1.1.1
25503 * Copyright(c) 2006-2007, Ext JS, LLC.
25505 * Originally Released Under LGPL - original licence link has changed is not relivant.
25508 * <script type="text/javascript">
25512 * @class Roo.JsonView
25513 * @extends Roo.View
25514 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25516 var view = new Roo.JsonView({
25517 container: "my-element",
25518 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25523 // listen for node click?
25524 view.on("click", function(vw, index, node, e){
25525 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25528 // direct load of JSON data
25529 view.load("foobar.php");
25531 // Example from my blog list
25532 var tpl = new Roo.Template(
25533 '<div class="entry">' +
25534 '<a class="entry-title" href="{link}">{title}</a>' +
25535 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25536 "</div><hr />"
25539 var moreView = new Roo.JsonView({
25540 container : "entry-list",
25544 moreView.on("beforerender", this.sortEntries, this);
25546 url: "/blog/get-posts.php",
25547 params: "allposts=true",
25548 text: "Loading Blog Entries..."
25552 * Note: old code is supported with arguments : (container, template, config)
25556 * Create a new JsonView
25558 * @param {Object} config The config object
25561 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25564 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25566 var um = this.el.getUpdateManager();
25567 um.setRenderer(this);
25568 um.on("update", this.onLoad, this);
25569 um.on("failure", this.onLoadException, this);
25572 * @event beforerender
25573 * Fires before rendering of the downloaded JSON data.
25574 * @param {Roo.JsonView} this
25575 * @param {Object} data The JSON data loaded
25579 * Fires when data is loaded.
25580 * @param {Roo.JsonView} this
25581 * @param {Object} data The JSON data loaded
25582 * @param {Object} response The raw Connect response object
25585 * @event loadexception
25586 * Fires when loading fails.
25587 * @param {Roo.JsonView} this
25588 * @param {Object} response The raw Connect response object
25591 'beforerender' : true,
25593 'loadexception' : true
25596 Roo.extend(Roo.JsonView, Roo.View, {
25598 * @type {String} The root property in the loaded JSON object that contains the data
25603 * Refreshes the view.
25605 refresh : function(){
25606 this.clearSelections();
25607 this.el.update("");
25609 var o = this.jsonData;
25610 if(o && o.length > 0){
25611 for(var i = 0, len = o.length; i < len; i++){
25612 var data = this.prepareData(o[i], i, o);
25613 html[html.length] = this.tpl.apply(data);
25616 html.push(this.emptyText);
25618 this.el.update(html.join(""));
25619 this.nodes = this.el.dom.childNodes;
25620 this.updateIndexes(0);
25624 * 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.
25625 * @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:
25628 url: "your-url.php",
25629 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25630 callback: yourFunction,
25631 scope: yourObject, //(optional scope)
25634 text: "Loading...",
25639 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25640 * 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.
25641 * @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}
25642 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25643 * @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.
25646 var um = this.el.getUpdateManager();
25647 um.update.apply(um, arguments);
25650 render : function(el, response){
25651 this.clearSelections();
25652 this.el.update("");
25655 o = Roo.util.JSON.decode(response.responseText);
25658 o = o[this.jsonRoot];
25663 * The current JSON data or null
25666 this.beforeRender();
25671 * Get the number of records in the current JSON dataset
25674 getCount : function(){
25675 return this.jsonData ? this.jsonData.length : 0;
25679 * Returns the JSON object for the specified node(s)
25680 * @param {HTMLElement/Array} node The node or an array of nodes
25681 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25682 * you get the JSON object for the node
25684 getNodeData : function(node){
25685 if(node instanceof Array){
25687 for(var i = 0, len = node.length; i < len; i++){
25688 data.push(this.getNodeData(node[i]));
25692 return this.jsonData[this.indexOf(node)] || null;
25695 beforeRender : function(){
25696 this.snapshot = this.jsonData;
25698 this.sort.apply(this, this.sortInfo);
25700 this.fireEvent("beforerender", this, this.jsonData);
25703 onLoad : function(el, o){
25704 this.fireEvent("load", this, this.jsonData, o);
25707 onLoadException : function(el, o){
25708 this.fireEvent("loadexception", this, o);
25712 * Filter the data by a specific property.
25713 * @param {String} property A property on your JSON objects
25714 * @param {String/RegExp} value Either string that the property values
25715 * should start with, or a RegExp to test against the property
25717 filter : function(property, value){
25720 var ss = this.snapshot;
25721 if(typeof value == "string"){
25722 var vlen = value.length;
25724 this.clearFilter();
25727 value = value.toLowerCase();
25728 for(var i = 0, len = ss.length; i < len; i++){
25730 if(o[property].substr(0, vlen).toLowerCase() == value){
25734 } else if(value.exec){ // regex?
25735 for(var i = 0, len = ss.length; i < len; i++){
25737 if(value.test(o[property])){
25744 this.jsonData = data;
25750 * Filter by a function. The passed function will be called with each
25751 * object in the current dataset. If the function returns true the value is kept,
25752 * otherwise it is filtered.
25753 * @param {Function} fn
25754 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25756 filterBy : function(fn, scope){
25759 var ss = this.snapshot;
25760 for(var i = 0, len = ss.length; i < len; i++){
25762 if(fn.call(scope || this, o)){
25766 this.jsonData = data;
25772 * Clears the current filter.
25774 clearFilter : function(){
25775 if(this.snapshot && this.jsonData != this.snapshot){
25776 this.jsonData = this.snapshot;
25783 * Sorts the data for this view and refreshes it.
25784 * @param {String} property A property on your JSON objects to sort on
25785 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25786 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25788 sort : function(property, dir, sortType){
25789 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25792 var dsc = dir && dir.toLowerCase() == "desc";
25793 var f = function(o1, o2){
25794 var v1 = sortType ? sortType(o1[p]) : o1[p];
25795 var v2 = sortType ? sortType(o2[p]) : o2[p];
25798 return dsc ? +1 : -1;
25799 } else if(v1 > v2){
25800 return dsc ? -1 : +1;
25805 this.jsonData.sort(f);
25807 if(this.jsonData != this.snapshot){
25808 this.snapshot.sort(f);
25814 * Ext JS Library 1.1.1
25815 * Copyright(c) 2006-2007, Ext JS, LLC.
25817 * Originally Released Under LGPL - original licence link has changed is not relivant.
25820 * <script type="text/javascript">
25825 * @class Roo.ColorPalette
25826 * @extends Roo.Component
25827 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25828 * Here's an example of typical usage:
25830 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25831 cp.render('my-div');
25833 cp.on('select', function(palette, selColor){
25834 // do something with selColor
25838 * Create a new ColorPalette
25839 * @param {Object} config The config object
25841 Roo.ColorPalette = function(config){
25842 Roo.ColorPalette.superclass.constructor.call(this, config);
25846 * Fires when a color is selected
25847 * @param {ColorPalette} this
25848 * @param {String} color The 6-digit color hex code (without the # symbol)
25854 this.on("select", this.handler, this.scope, true);
25857 Roo.extend(Roo.ColorPalette, Roo.Component, {
25859 * @cfg {String} itemCls
25860 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25862 itemCls : "x-color-palette",
25864 * @cfg {String} value
25865 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25866 * the hex codes are case-sensitive.
25869 clickEvent:'click',
25871 ctype: "Roo.ColorPalette",
25874 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25876 allowReselect : false,
25879 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25880 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25881 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25882 * of colors with the width setting until the box is symmetrical.</p>
25883 * <p>You can override individual colors if needed:</p>
25885 var cp = new Roo.ColorPalette();
25886 cp.colors[0] = "FF0000"; // change the first box to red
25889 Or you can provide a custom array of your own for complete control:
25891 var cp = new Roo.ColorPalette();
25892 cp.colors = ["000000", "993300", "333300"];
25897 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25898 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25899 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25900 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25901 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25905 onRender : function(container, position){
25906 var t = new Roo.MasterTemplate(
25907 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25909 var c = this.colors;
25910 for(var i = 0, len = c.length; i < len; i++){
25913 var el = document.createElement("div");
25914 el.className = this.itemCls;
25916 container.dom.insertBefore(el, position);
25917 this.el = Roo.get(el);
25918 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25919 if(this.clickEvent != 'click'){
25920 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25925 afterRender : function(){
25926 Roo.ColorPalette.superclass.afterRender.call(this);
25928 var s = this.value;
25935 handleClick : function(e, t){
25936 e.preventDefault();
25937 if(!this.disabled){
25938 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25939 this.select(c.toUpperCase());
25944 * Selects the specified color in the palette (fires the select event)
25945 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25947 select : function(color){
25948 color = color.replace("#", "");
25949 if(color != this.value || this.allowReselect){
25952 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25954 el.child("a.color-"+color).addClass("x-color-palette-sel");
25955 this.value = color;
25956 this.fireEvent("select", this, color);
25961 * Ext JS Library 1.1.1
25962 * Copyright(c) 2006-2007, Ext JS, LLC.
25964 * Originally Released Under LGPL - original licence link has changed is not relivant.
25967 * <script type="text/javascript">
25971 * @class Roo.DatePicker
25972 * @extends Roo.Component
25973 * Simple date picker class.
25975 * Create a new DatePicker
25976 * @param {Object} config The config object
25978 Roo.DatePicker = function(config){
25979 Roo.DatePicker.superclass.constructor.call(this, config);
25981 this.value = config && config.value ?
25982 config.value.clearTime() : new Date().clearTime();
25987 * Fires when a date is selected
25988 * @param {DatePicker} this
25989 * @param {Date} date The selected date
25993 * @event monthchange
25994 * Fires when the displayed month changes
25995 * @param {DatePicker} this
25996 * @param {Date} date The selected month
25998 'monthchange': true
26002 this.on("select", this.handler, this.scope || this);
26004 // build the disabledDatesRE
26005 if(!this.disabledDatesRE && this.disabledDates){
26006 var dd = this.disabledDates;
26008 for(var i = 0; i < dd.length; i++){
26010 if(i != dd.length-1) re += "|";
26012 this.disabledDatesRE = new RegExp(re + ")");
26016 Roo.extend(Roo.DatePicker, Roo.Component, {
26018 * @cfg {String} todayText
26019 * The text to display on the button that selects the current date (defaults to "Today")
26021 todayText : "Today",
26023 * @cfg {String} okText
26024 * The text to display on the ok button
26026 okText : " OK ", //   to give the user extra clicking room
26028 * @cfg {String} cancelText
26029 * The text to display on the cancel button
26031 cancelText : "Cancel",
26033 * @cfg {String} todayTip
26034 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
26036 todayTip : "{0} (Spacebar)",
26038 * @cfg {Date} minDate
26039 * Minimum allowable date (JavaScript date object, defaults to null)
26043 * @cfg {Date} maxDate
26044 * Maximum allowable date (JavaScript date object, defaults to null)
26048 * @cfg {String} minText
26049 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
26051 minText : "This date is before the minimum date",
26053 * @cfg {String} maxText
26054 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
26056 maxText : "This date is after the maximum date",
26058 * @cfg {String} format
26059 * The default date format string which can be overriden for localization support. The format must be
26060 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26064 * @cfg {Array} disabledDays
26065 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26067 disabledDays : null,
26069 * @cfg {String} disabledDaysText
26070 * The tooltip to display when the date falls on a disabled day (defaults to "")
26072 disabledDaysText : "",
26074 * @cfg {RegExp} disabledDatesRE
26075 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26077 disabledDatesRE : null,
26079 * @cfg {String} disabledDatesText
26080 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26082 disabledDatesText : "",
26084 * @cfg {Boolean} constrainToViewport
26085 * True to constrain the date picker to the viewport (defaults to true)
26087 constrainToViewport : true,
26089 * @cfg {Array} monthNames
26090 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26092 monthNames : Date.monthNames,
26094 * @cfg {Array} dayNames
26095 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26097 dayNames : Date.dayNames,
26099 * @cfg {String} nextText
26100 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26102 nextText: 'Next Month (Control+Right)',
26104 * @cfg {String} prevText
26105 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26107 prevText: 'Previous Month (Control+Left)',
26109 * @cfg {String} monthYearText
26110 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26112 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26114 * @cfg {Number} startDay
26115 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26119 * @cfg {Bool} showClear
26120 * Show a clear button (usefull for date form elements that can be blank.)
26126 * Sets the value of the date field
26127 * @param {Date} value The date to set
26129 setValue : function(value){
26130 var old = this.value;
26132 if (typeof(value) == 'string') {
26134 value = Date.parseDate(value, this.format);
26137 value = new Date();
26140 this.value = value.clearTime(true);
26142 this.update(this.value);
26147 * Gets the current selected value of the date field
26148 * @return {Date} The selected date
26150 getValue : function(){
26155 focus : function(){
26157 this.update(this.activeDate);
26162 onRender : function(container, position){
26165 '<table cellspacing="0">',
26166 '<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>',
26167 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26168 var dn = this.dayNames;
26169 for(var i = 0; i < 7; i++){
26170 var d = this.startDay+i;
26174 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26176 m[m.length] = "</tr></thead><tbody><tr>";
26177 for(var i = 0; i < 42; i++) {
26178 if(i % 7 == 0 && i != 0){
26179 m[m.length] = "</tr><tr>";
26181 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26183 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26184 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26186 var el = document.createElement("div");
26187 el.className = "x-date-picker";
26188 el.innerHTML = m.join("");
26190 container.dom.insertBefore(el, position);
26192 this.el = Roo.get(el);
26193 this.eventEl = Roo.get(el.firstChild);
26195 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26196 handler: this.showPrevMonth,
26198 preventDefault:true,
26202 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26203 handler: this.showNextMonth,
26205 preventDefault:true,
26209 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26211 this.monthPicker = this.el.down('div.x-date-mp');
26212 this.monthPicker.enableDisplayMode('block');
26214 var kn = new Roo.KeyNav(this.eventEl, {
26215 "left" : function(e){
26217 this.showPrevMonth() :
26218 this.update(this.activeDate.add("d", -1));
26221 "right" : function(e){
26223 this.showNextMonth() :
26224 this.update(this.activeDate.add("d", 1));
26227 "up" : function(e){
26229 this.showNextYear() :
26230 this.update(this.activeDate.add("d", -7));
26233 "down" : function(e){
26235 this.showPrevYear() :
26236 this.update(this.activeDate.add("d", 7));
26239 "pageUp" : function(e){
26240 this.showNextMonth();
26243 "pageDown" : function(e){
26244 this.showPrevMonth();
26247 "enter" : function(e){
26248 e.stopPropagation();
26255 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26257 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26259 this.el.unselectable();
26261 this.cells = this.el.select("table.x-date-inner tbody td");
26262 this.textNodes = this.el.query("table.x-date-inner tbody span");
26264 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26266 tooltip: this.monthYearText
26269 this.mbtn.on('click', this.showMonthPicker, this);
26270 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26273 var today = (new Date()).dateFormat(this.format);
26275 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26276 if (this.showClear) {
26277 baseTb.add( new Roo.Toolbar.Fill());
26280 text: String.format(this.todayText, today),
26281 tooltip: String.format(this.todayTip, today),
26282 handler: this.selectToday,
26286 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26289 if (this.showClear) {
26291 baseTb.add( new Roo.Toolbar.Fill());
26294 cls: 'x-btn-icon x-btn-clear',
26295 handler: function() {
26297 this.fireEvent("select", this, '');
26307 this.update(this.value);
26310 createMonthPicker : function(){
26311 if(!this.monthPicker.dom.firstChild){
26312 var buf = ['<table border="0" cellspacing="0">'];
26313 for(var i = 0; i < 6; i++){
26315 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26316 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26318 '<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>' :
26319 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26323 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26325 '</button><button type="button" class="x-date-mp-cancel">',
26327 '</button></td></tr>',
26330 this.monthPicker.update(buf.join(''));
26331 this.monthPicker.on('click', this.onMonthClick, this);
26332 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26334 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26335 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26337 this.mpMonths.each(function(m, a, i){
26340 m.dom.xmonth = 5 + Math.round(i * .5);
26342 m.dom.xmonth = Math.round((i-1) * .5);
26348 showMonthPicker : function(){
26349 this.createMonthPicker();
26350 var size = this.el.getSize();
26351 this.monthPicker.setSize(size);
26352 this.monthPicker.child('table').setSize(size);
26354 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26355 this.updateMPMonth(this.mpSelMonth);
26356 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26357 this.updateMPYear(this.mpSelYear);
26359 this.monthPicker.slideIn('t', {duration:.2});
26362 updateMPYear : function(y){
26364 var ys = this.mpYears.elements;
26365 for(var i = 1; i <= 10; i++){
26366 var td = ys[i-1], y2;
26368 y2 = y + Math.round(i * .5);
26369 td.firstChild.innerHTML = y2;
26372 y2 = y - (5-Math.round(i * .5));
26373 td.firstChild.innerHTML = y2;
26376 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26380 updateMPMonth : function(sm){
26381 this.mpMonths.each(function(m, a, i){
26382 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26386 selectMPMonth: function(m){
26390 onMonthClick : function(e, t){
26392 var el = new Roo.Element(t), pn;
26393 if(el.is('button.x-date-mp-cancel')){
26394 this.hideMonthPicker();
26396 else if(el.is('button.x-date-mp-ok')){
26397 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26398 this.hideMonthPicker();
26400 else if(pn = el.up('td.x-date-mp-month', 2)){
26401 this.mpMonths.removeClass('x-date-mp-sel');
26402 pn.addClass('x-date-mp-sel');
26403 this.mpSelMonth = pn.dom.xmonth;
26405 else if(pn = el.up('td.x-date-mp-year', 2)){
26406 this.mpYears.removeClass('x-date-mp-sel');
26407 pn.addClass('x-date-mp-sel');
26408 this.mpSelYear = pn.dom.xyear;
26410 else if(el.is('a.x-date-mp-prev')){
26411 this.updateMPYear(this.mpyear-10);
26413 else if(el.is('a.x-date-mp-next')){
26414 this.updateMPYear(this.mpyear+10);
26418 onMonthDblClick : function(e, t){
26420 var el = new Roo.Element(t), pn;
26421 if(pn = el.up('td.x-date-mp-month', 2)){
26422 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26423 this.hideMonthPicker();
26425 else if(pn = el.up('td.x-date-mp-year', 2)){
26426 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26427 this.hideMonthPicker();
26431 hideMonthPicker : function(disableAnim){
26432 if(this.monthPicker){
26433 if(disableAnim === true){
26434 this.monthPicker.hide();
26436 this.monthPicker.slideOut('t', {duration:.2});
26442 showPrevMonth : function(e){
26443 this.update(this.activeDate.add("mo", -1));
26447 showNextMonth : function(e){
26448 this.update(this.activeDate.add("mo", 1));
26452 showPrevYear : function(){
26453 this.update(this.activeDate.add("y", -1));
26457 showNextYear : function(){
26458 this.update(this.activeDate.add("y", 1));
26462 handleMouseWheel : function(e){
26463 var delta = e.getWheelDelta();
26465 this.showPrevMonth();
26467 } else if(delta < 0){
26468 this.showNextMonth();
26474 handleDateClick : function(e, t){
26476 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26477 this.setValue(new Date(t.dateValue));
26478 this.fireEvent("select", this, this.value);
26483 selectToday : function(){
26484 this.setValue(new Date().clearTime());
26485 this.fireEvent("select", this, this.value);
26489 update : function(date)
26491 var vd = this.activeDate;
26492 this.activeDate = date;
26494 var t = date.getTime();
26495 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26496 this.cells.removeClass("x-date-selected");
26497 this.cells.each(function(c){
26498 if(c.dom.firstChild.dateValue == t){
26499 c.addClass("x-date-selected");
26500 setTimeout(function(){
26501 try{c.dom.firstChild.focus();}catch(e){}
26510 var days = date.getDaysInMonth();
26511 var firstOfMonth = date.getFirstDateOfMonth();
26512 var startingPos = firstOfMonth.getDay()-this.startDay;
26514 if(startingPos <= this.startDay){
26518 var pm = date.add("mo", -1);
26519 var prevStart = pm.getDaysInMonth()-startingPos;
26521 var cells = this.cells.elements;
26522 var textEls = this.textNodes;
26523 days += startingPos;
26525 // convert everything to numbers so it's fast
26526 var day = 86400000;
26527 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26528 var today = new Date().clearTime().getTime();
26529 var sel = date.clearTime().getTime();
26530 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26531 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26532 var ddMatch = this.disabledDatesRE;
26533 var ddText = this.disabledDatesText;
26534 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26535 var ddaysText = this.disabledDaysText;
26536 var format = this.format;
26538 var setCellClass = function(cal, cell){
26540 var t = d.getTime();
26541 cell.firstChild.dateValue = t;
26543 cell.className += " x-date-today";
26544 cell.title = cal.todayText;
26547 cell.className += " x-date-selected";
26548 setTimeout(function(){
26549 try{cell.firstChild.focus();}catch(e){}
26554 cell.className = " x-date-disabled";
26555 cell.title = cal.minText;
26559 cell.className = " x-date-disabled";
26560 cell.title = cal.maxText;
26564 if(ddays.indexOf(d.getDay()) != -1){
26565 cell.title = ddaysText;
26566 cell.className = " x-date-disabled";
26569 if(ddMatch && format){
26570 var fvalue = d.dateFormat(format);
26571 if(ddMatch.test(fvalue)){
26572 cell.title = ddText.replace("%0", fvalue);
26573 cell.className = " x-date-disabled";
26579 for(; i < startingPos; i++) {
26580 textEls[i].innerHTML = (++prevStart);
26581 d.setDate(d.getDate()+1);
26582 cells[i].className = "x-date-prevday";
26583 setCellClass(this, cells[i]);
26585 for(; i < days; i++){
26586 intDay = i - startingPos + 1;
26587 textEls[i].innerHTML = (intDay);
26588 d.setDate(d.getDate()+1);
26589 cells[i].className = "x-date-active";
26590 setCellClass(this, cells[i]);
26593 for(; i < 42; i++) {
26594 textEls[i].innerHTML = (++extraDays);
26595 d.setDate(d.getDate()+1);
26596 cells[i].className = "x-date-nextday";
26597 setCellClass(this, cells[i]);
26600 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26601 this.fireEvent('monthchange', this, date);
26603 if(!this.internalRender){
26604 var main = this.el.dom.firstChild;
26605 var w = main.offsetWidth;
26606 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26607 Roo.fly(main).setWidth(w);
26608 this.internalRender = true;
26609 // opera does not respect the auto grow header center column
26610 // then, after it gets a width opera refuses to recalculate
26611 // without a second pass
26612 if(Roo.isOpera && !this.secondPass){
26613 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26614 this.secondPass = true;
26615 this.update.defer(10, this, [date]);
26623 * Ext JS Library 1.1.1
26624 * Copyright(c) 2006-2007, Ext JS, LLC.
26626 * Originally Released Under LGPL - original licence link has changed is not relivant.
26629 * <script type="text/javascript">
26632 * @class Roo.TabPanel
26633 * @extends Roo.util.Observable
26634 * A lightweight tab container.
26638 // basic tabs 1, built from existing content
26639 var tabs = new Roo.TabPanel("tabs1");
26640 tabs.addTab("script", "View Script");
26641 tabs.addTab("markup", "View Markup");
26642 tabs.activate("script");
26644 // more advanced tabs, built from javascript
26645 var jtabs = new Roo.TabPanel("jtabs");
26646 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26648 // set up the UpdateManager
26649 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26650 var updater = tab2.getUpdateManager();
26651 updater.setDefaultUrl("ajax1.htm");
26652 tab2.on('activate', updater.refresh, updater, true);
26654 // Use setUrl for Ajax loading
26655 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26656 tab3.setUrl("ajax2.htm", null, true);
26659 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26662 jtabs.activate("jtabs-1");
26665 * Create a new TabPanel.
26666 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26667 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26669 Roo.TabPanel = function(container, config){
26671 * The container element for this TabPanel.
26672 * @type Roo.Element
26674 this.el = Roo.get(container, true);
26676 if(typeof config == "boolean"){
26677 this.tabPosition = config ? "bottom" : "top";
26679 Roo.apply(this, config);
26682 if(this.tabPosition == "bottom"){
26683 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26684 this.el.addClass("x-tabs-bottom");
26686 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26687 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26688 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26690 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26692 if(this.tabPosition != "bottom"){
26693 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26694 * @type Roo.Element
26696 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26697 this.el.addClass("x-tabs-top");
26701 this.bodyEl.setStyle("position", "relative");
26703 this.active = null;
26704 this.activateDelegate = this.activate.createDelegate(this);
26709 * Fires when the active tab changes
26710 * @param {Roo.TabPanel} this
26711 * @param {Roo.TabPanelItem} activePanel The new active tab
26715 * @event beforetabchange
26716 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26717 * @param {Roo.TabPanel} this
26718 * @param {Object} e Set cancel to true on this object to cancel the tab change
26719 * @param {Roo.TabPanelItem} tab The tab being changed to
26721 "beforetabchange" : true
26724 Roo.EventManager.onWindowResize(this.onResize, this);
26725 this.cpad = this.el.getPadding("lr");
26726 this.hiddenCount = 0;
26729 // toolbar on the tabbar support...
26730 if (this.toolbar) {
26731 var tcfg = this.toolbar;
26732 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26733 this.toolbar = new Roo.Toolbar(tcfg);
26734 if (Roo.isSafari) {
26735 var tbl = tcfg.container.child('table', true);
26736 tbl.setAttribute('width', '100%');
26743 Roo.TabPanel.superclass.constructor.call(this);
26746 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26748 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26750 tabPosition : "top",
26752 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26754 currentTabWidth : 0,
26756 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26760 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26764 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26766 preferredTabWidth : 175,
26768 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26770 resizeTabs : false,
26772 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26774 monitorResize : true,
26776 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26781 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26782 * @param {String} id The id of the div to use <b>or create</b>
26783 * @param {String} text The text for the tab
26784 * @param {String} content (optional) Content to put in the TabPanelItem body
26785 * @param {Boolean} closable (optional) True to create a close icon on the tab
26786 * @return {Roo.TabPanelItem} The created TabPanelItem
26788 addTab : function(id, text, content, closable){
26789 var item = new Roo.TabPanelItem(this, id, text, closable);
26790 this.addTabItem(item);
26792 item.setContent(content);
26798 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26799 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26800 * @return {Roo.TabPanelItem}
26802 getTab : function(id){
26803 return this.items[id];
26807 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26808 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26810 hideTab : function(id){
26811 var t = this.items[id];
26814 this.hiddenCount++;
26815 this.autoSizeTabs();
26820 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26821 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26823 unhideTab : function(id){
26824 var t = this.items[id];
26826 t.setHidden(false);
26827 this.hiddenCount--;
26828 this.autoSizeTabs();
26833 * Adds an existing {@link Roo.TabPanelItem}.
26834 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26836 addTabItem : function(item){
26837 this.items[item.id] = item;
26838 this.items.push(item);
26839 if(this.resizeTabs){
26840 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26841 this.autoSizeTabs();
26848 * Removes a {@link Roo.TabPanelItem}.
26849 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26851 removeTab : function(id){
26852 var items = this.items;
26853 var tab = items[id];
26854 if(!tab) { return; }
26855 var index = items.indexOf(tab);
26856 if(this.active == tab && items.length > 1){
26857 var newTab = this.getNextAvailable(index);
26862 this.stripEl.dom.removeChild(tab.pnode.dom);
26863 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26864 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26866 items.splice(index, 1);
26867 delete this.items[tab.id];
26868 tab.fireEvent("close", tab);
26869 tab.purgeListeners();
26870 this.autoSizeTabs();
26873 getNextAvailable : function(start){
26874 var items = this.items;
26876 // look for a next tab that will slide over to
26877 // replace the one being removed
26878 while(index < items.length){
26879 var item = items[++index];
26880 if(item && !item.isHidden()){
26884 // if one isn't found select the previous tab (on the left)
26887 var item = items[--index];
26888 if(item && !item.isHidden()){
26896 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26897 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26899 disableTab : function(id){
26900 var tab = this.items[id];
26901 if(tab && this.active != tab){
26907 * Enables a {@link Roo.TabPanelItem} that is disabled.
26908 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26910 enableTab : function(id){
26911 var tab = this.items[id];
26916 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26917 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26918 * @return {Roo.TabPanelItem} The TabPanelItem.
26920 activate : function(id){
26921 var tab = this.items[id];
26925 if(tab == this.active || tab.disabled){
26929 this.fireEvent("beforetabchange", this, e, tab);
26930 if(e.cancel !== true && !tab.disabled){
26932 this.active.hide();
26934 this.active = this.items[id];
26935 this.active.show();
26936 this.fireEvent("tabchange", this, this.active);
26942 * Gets the active {@link Roo.TabPanelItem}.
26943 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26945 getActiveTab : function(){
26946 return this.active;
26950 * Updates the tab body element to fit the height of the container element
26951 * for overflow scrolling
26952 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26954 syncHeight : function(targetHeight){
26955 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26956 var bm = this.bodyEl.getMargins();
26957 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26958 this.bodyEl.setHeight(newHeight);
26962 onResize : function(){
26963 if(this.monitorResize){
26964 this.autoSizeTabs();
26969 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26971 beginUpdate : function(){
26972 this.updating = true;
26976 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26978 endUpdate : function(){
26979 this.updating = false;
26980 this.autoSizeTabs();
26984 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26986 autoSizeTabs : function(){
26987 var count = this.items.length;
26988 var vcount = count - this.hiddenCount;
26989 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26990 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26991 var availWidth = Math.floor(w / vcount);
26992 var b = this.stripBody;
26993 if(b.getWidth() > w){
26994 var tabs = this.items;
26995 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26996 if(availWidth < this.minTabWidth){
26997 /*if(!this.sleft){ // incomplete scrolling code
26998 this.createScrollButtons();
27001 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
27004 if(this.currentTabWidth < this.preferredTabWidth){
27005 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
27011 * Returns the number of tabs in this TabPanel.
27014 getCount : function(){
27015 return this.items.length;
27019 * Resizes all the tabs to the passed width
27020 * @param {Number} The new width
27022 setTabWidth : function(width){
27023 this.currentTabWidth = width;
27024 for(var i = 0, len = this.items.length; i < len; i++) {
27025 if(!this.items[i].isHidden())this.items[i].setWidth(width);
27030 * Destroys this TabPanel
27031 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
27033 destroy : function(removeEl){
27034 Roo.EventManager.removeResizeListener(this.onResize, this);
27035 for(var i = 0, len = this.items.length; i < len; i++){
27036 this.items[i].purgeListeners();
27038 if(removeEl === true){
27039 this.el.update("");
27046 * @class Roo.TabPanelItem
27047 * @extends Roo.util.Observable
27048 * Represents an individual item (tab plus body) in a TabPanel.
27049 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
27050 * @param {String} id The id of this TabPanelItem
27051 * @param {String} text The text for the tab of this TabPanelItem
27052 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
27054 Roo.TabPanelItem = function(tabPanel, id, text, closable){
27056 * The {@link Roo.TabPanel} this TabPanelItem belongs to
27057 * @type Roo.TabPanel
27059 this.tabPanel = tabPanel;
27061 * The id for this TabPanelItem
27066 this.disabled = false;
27070 this.loaded = false;
27071 this.closable = closable;
27074 * The body element for this TabPanelItem.
27075 * @type Roo.Element
27077 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27078 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27079 this.bodyEl.setStyle("display", "block");
27080 this.bodyEl.setStyle("zoom", "1");
27083 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27085 this.el = Roo.get(els.el, true);
27086 this.inner = Roo.get(els.inner, true);
27087 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27088 this.pnode = Roo.get(els.el.parentNode, true);
27089 this.el.on("mousedown", this.onTabMouseDown, this);
27090 this.el.on("click", this.onTabClick, this);
27093 var c = Roo.get(els.close, true);
27094 c.dom.title = this.closeText;
27095 c.addClassOnOver("close-over");
27096 c.on("click", this.closeClick, this);
27102 * Fires when this tab becomes the active tab.
27103 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27104 * @param {Roo.TabPanelItem} this
27108 * @event beforeclose
27109 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27110 * @param {Roo.TabPanelItem} this
27111 * @param {Object} e Set cancel to true on this object to cancel the close.
27113 "beforeclose": true,
27116 * Fires when this tab is closed.
27117 * @param {Roo.TabPanelItem} this
27121 * @event deactivate
27122 * Fires when this tab is no longer the active tab.
27123 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27124 * @param {Roo.TabPanelItem} this
27126 "deactivate" : true
27128 this.hidden = false;
27130 Roo.TabPanelItem.superclass.constructor.call(this);
27133 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27134 purgeListeners : function(){
27135 Roo.util.Observable.prototype.purgeListeners.call(this);
27136 this.el.removeAllListeners();
27139 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27142 this.pnode.addClass("on");
27145 this.tabPanel.stripWrap.repaint();
27147 this.fireEvent("activate", this.tabPanel, this);
27151 * Returns true if this tab is the active tab.
27152 * @return {Boolean}
27154 isActive : function(){
27155 return this.tabPanel.getActiveTab() == this;
27159 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27162 this.pnode.removeClass("on");
27164 this.fireEvent("deactivate", this.tabPanel, this);
27167 hideAction : function(){
27168 this.bodyEl.hide();
27169 this.bodyEl.setStyle("position", "absolute");
27170 this.bodyEl.setLeft("-20000px");
27171 this.bodyEl.setTop("-20000px");
27174 showAction : function(){
27175 this.bodyEl.setStyle("position", "relative");
27176 this.bodyEl.setTop("");
27177 this.bodyEl.setLeft("");
27178 this.bodyEl.show();
27182 * Set the tooltip for the tab.
27183 * @param {String} tooltip The tab's tooltip
27185 setTooltip : function(text){
27186 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27187 this.textEl.dom.qtip = text;
27188 this.textEl.dom.removeAttribute('title');
27190 this.textEl.dom.title = text;
27194 onTabClick : function(e){
27195 e.preventDefault();
27196 this.tabPanel.activate(this.id);
27199 onTabMouseDown : function(e){
27200 e.preventDefault();
27201 this.tabPanel.activate(this.id);
27204 getWidth : function(){
27205 return this.inner.getWidth();
27208 setWidth : function(width){
27209 var iwidth = width - this.pnode.getPadding("lr");
27210 this.inner.setWidth(iwidth);
27211 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27212 this.pnode.setWidth(width);
27216 * Show or hide the tab
27217 * @param {Boolean} hidden True to hide or false to show.
27219 setHidden : function(hidden){
27220 this.hidden = hidden;
27221 this.pnode.setStyle("display", hidden ? "none" : "");
27225 * Returns true if this tab is "hidden"
27226 * @return {Boolean}
27228 isHidden : function(){
27229 return this.hidden;
27233 * Returns the text for this tab
27236 getText : function(){
27240 autoSize : function(){
27241 //this.el.beginMeasure();
27242 this.textEl.setWidth(1);
27244 * #2804 [new] Tabs in Roojs
27245 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27247 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27248 //this.el.endMeasure();
27252 * Sets the text for the tab (Note: this also sets the tooltip text)
27253 * @param {String} text The tab's text and tooltip
27255 setText : function(text){
27257 this.textEl.update(text);
27258 this.setTooltip(text);
27259 if(!this.tabPanel.resizeTabs){
27264 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27266 activate : function(){
27267 this.tabPanel.activate(this.id);
27271 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27273 disable : function(){
27274 if(this.tabPanel.active != this){
27275 this.disabled = true;
27276 this.pnode.addClass("disabled");
27281 * Enables this TabPanelItem if it was previously disabled.
27283 enable : function(){
27284 this.disabled = false;
27285 this.pnode.removeClass("disabled");
27289 * Sets the content for this TabPanelItem.
27290 * @param {String} content The content
27291 * @param {Boolean} loadScripts true to look for and load scripts
27293 setContent : function(content, loadScripts){
27294 this.bodyEl.update(content, loadScripts);
27298 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27299 * @return {Roo.UpdateManager} The UpdateManager
27301 getUpdateManager : function(){
27302 return this.bodyEl.getUpdateManager();
27306 * Set a URL to be used to load the content for this TabPanelItem.
27307 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27308 * @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)
27309 * @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)
27310 * @return {Roo.UpdateManager} The UpdateManager
27312 setUrl : function(url, params, loadOnce){
27313 if(this.refreshDelegate){
27314 this.un('activate', this.refreshDelegate);
27316 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27317 this.on("activate", this.refreshDelegate);
27318 return this.bodyEl.getUpdateManager();
27322 _handleRefresh : function(url, params, loadOnce){
27323 if(!loadOnce || !this.loaded){
27324 var updater = this.bodyEl.getUpdateManager();
27325 updater.update(url, params, this._setLoaded.createDelegate(this));
27330 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27331 * Will fail silently if the setUrl method has not been called.
27332 * This does not activate the panel, just updates its content.
27334 refresh : function(){
27335 if(this.refreshDelegate){
27336 this.loaded = false;
27337 this.refreshDelegate();
27342 _setLoaded : function(){
27343 this.loaded = true;
27347 closeClick : function(e){
27350 this.fireEvent("beforeclose", this, o);
27351 if(o.cancel !== true){
27352 this.tabPanel.removeTab(this.id);
27356 * The text displayed in the tooltip for the close icon.
27359 closeText : "Close this tab"
27363 Roo.TabPanel.prototype.createStrip = function(container){
27364 var strip = document.createElement("div");
27365 strip.className = "x-tabs-wrap";
27366 container.appendChild(strip);
27370 Roo.TabPanel.prototype.createStripList = function(strip){
27371 // div wrapper for retard IE
27372 // returns the "tr" element.
27373 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27374 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27375 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27376 return strip.firstChild.firstChild.firstChild.firstChild;
27379 Roo.TabPanel.prototype.createBody = function(container){
27380 var body = document.createElement("div");
27381 Roo.id(body, "tab-body");
27382 Roo.fly(body).addClass("x-tabs-body");
27383 container.appendChild(body);
27387 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27388 var body = Roo.getDom(id);
27390 body = document.createElement("div");
27393 Roo.fly(body).addClass("x-tabs-item-body");
27394 bodyEl.insertBefore(body, bodyEl.firstChild);
27398 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27399 var td = document.createElement("td");
27400 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27401 //stripEl.appendChild(td);
27403 td.className = "x-tabs-closable";
27404 if(!this.closeTpl){
27405 this.closeTpl = new Roo.Template(
27406 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27407 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27408 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27411 var el = this.closeTpl.overwrite(td, {"text": text});
27412 var close = el.getElementsByTagName("div")[0];
27413 var inner = el.getElementsByTagName("em")[0];
27414 return {"el": el, "close": close, "inner": inner};
27417 this.tabTpl = new Roo.Template(
27418 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27419 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27422 var el = this.tabTpl.overwrite(td, {"text": text});
27423 var inner = el.getElementsByTagName("em")[0];
27424 return {"el": el, "inner": inner};
27428 * Ext JS Library 1.1.1
27429 * Copyright(c) 2006-2007, Ext JS, LLC.
27431 * Originally Released Under LGPL - original licence link has changed is not relivant.
27434 * <script type="text/javascript">
27438 * @class Roo.Button
27439 * @extends Roo.util.Observable
27440 * Simple Button class
27441 * @cfg {String} text The button text
27442 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27443 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27444 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27445 * @cfg {Object} scope The scope of the handler
27446 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27447 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27448 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27449 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27450 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27451 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27452 applies if enableToggle = true)
27453 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27454 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27455 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27457 * Create a new button
27458 * @param {Object} config The config object
27460 Roo.Button = function(renderTo, config)
27464 renderTo = config.renderTo || false;
27467 Roo.apply(this, config);
27471 * Fires when this button is clicked
27472 * @param {Button} this
27473 * @param {EventObject} e The click event
27478 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27479 * @param {Button} this
27480 * @param {Boolean} pressed
27485 * Fires when the mouse hovers over the button
27486 * @param {Button} this
27487 * @param {Event} e The event object
27489 'mouseover' : true,
27492 * Fires when the mouse exits the button
27493 * @param {Button} this
27494 * @param {Event} e The event object
27499 * Fires when the button is rendered
27500 * @param {Button} this
27505 this.menu = Roo.menu.MenuMgr.get(this.menu);
27507 // register listeners first!! - so render can be captured..
27508 Roo.util.Observable.call(this);
27510 this.render(renderTo);
27516 Roo.extend(Roo.Button, Roo.util.Observable, {
27522 * Read-only. True if this button is hidden
27527 * Read-only. True if this button is disabled
27532 * Read-only. True if this button is pressed (only if enableToggle = true)
27538 * @cfg {Number} tabIndex
27539 * The DOM tabIndex for this button (defaults to undefined)
27541 tabIndex : undefined,
27544 * @cfg {Boolean} enableToggle
27545 * True to enable pressed/not pressed toggling (defaults to false)
27547 enableToggle: false,
27549 * @cfg {Mixed} menu
27550 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27554 * @cfg {String} menuAlign
27555 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27557 menuAlign : "tl-bl?",
27560 * @cfg {String} iconCls
27561 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27563 iconCls : undefined,
27565 * @cfg {String} type
27566 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27571 menuClassTarget: 'tr',
27574 * @cfg {String} clickEvent
27575 * The type of event to map to the button's event handler (defaults to 'click')
27577 clickEvent : 'click',
27580 * @cfg {Boolean} handleMouseEvents
27581 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27583 handleMouseEvents : true,
27586 * @cfg {String} tooltipType
27587 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27589 tooltipType : 'qtip',
27592 * @cfg {String} cls
27593 * A CSS class to apply to the button's main element.
27597 * @cfg {Roo.Template} template (Optional)
27598 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27599 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27600 * require code modifications if required elements (e.g. a button) aren't present.
27604 render : function(renderTo){
27606 if(this.hideParent){
27607 this.parentEl = Roo.get(renderTo);
27609 if(!this.dhconfig){
27610 if(!this.template){
27611 if(!Roo.Button.buttonTemplate){
27612 // hideous table template
27613 Roo.Button.buttonTemplate = new Roo.Template(
27614 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27615 '<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>',
27616 "</tr></tbody></table>");
27618 this.template = Roo.Button.buttonTemplate;
27620 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27621 var btnEl = btn.child("button:first");
27622 btnEl.on('focus', this.onFocus, this);
27623 btnEl.on('blur', this.onBlur, this);
27625 btn.addClass(this.cls);
27628 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27631 btnEl.addClass(this.iconCls);
27633 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27636 if(this.tabIndex !== undefined){
27637 btnEl.dom.tabIndex = this.tabIndex;
27640 if(typeof this.tooltip == 'object'){
27641 Roo.QuickTips.tips(Roo.apply({
27645 btnEl.dom[this.tooltipType] = this.tooltip;
27649 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27653 this.el.dom.id = this.el.id = this.id;
27656 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27657 this.menu.on("show", this.onMenuShow, this);
27658 this.menu.on("hide", this.onMenuHide, this);
27660 btn.addClass("x-btn");
27661 if(Roo.isIE && !Roo.isIE7){
27662 this.autoWidth.defer(1, this);
27666 if(this.handleMouseEvents){
27667 btn.on("mouseover", this.onMouseOver, this);
27668 btn.on("mouseout", this.onMouseOut, this);
27669 btn.on("mousedown", this.onMouseDown, this);
27671 btn.on(this.clickEvent, this.onClick, this);
27672 //btn.on("mouseup", this.onMouseUp, this);
27679 Roo.ButtonToggleMgr.register(this);
27681 this.el.addClass("x-btn-pressed");
27684 var repeater = new Roo.util.ClickRepeater(btn,
27685 typeof this.repeat == "object" ? this.repeat : {}
27687 repeater.on("click", this.onClick, this);
27690 this.fireEvent('render', this);
27694 * Returns the button's underlying element
27695 * @return {Roo.Element} The element
27697 getEl : function(){
27702 * Destroys this Button and removes any listeners.
27704 destroy : function(){
27705 Roo.ButtonToggleMgr.unregister(this);
27706 this.el.removeAllListeners();
27707 this.purgeListeners();
27712 autoWidth : function(){
27714 this.el.setWidth("auto");
27715 if(Roo.isIE7 && Roo.isStrict){
27716 var ib = this.el.child('button');
27717 if(ib && ib.getWidth() > 20){
27719 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27724 this.el.beginMeasure();
27726 if(this.el.getWidth() < this.minWidth){
27727 this.el.setWidth(this.minWidth);
27730 this.el.endMeasure();
27737 * Assigns this button's click handler
27738 * @param {Function} handler The function to call when the button is clicked
27739 * @param {Object} scope (optional) Scope for the function passed in
27741 setHandler : function(handler, scope){
27742 this.handler = handler;
27743 this.scope = scope;
27747 * Sets this button's text
27748 * @param {String} text The button text
27750 setText : function(text){
27753 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27759 * Gets the text for this button
27760 * @return {String} The button text
27762 getText : function(){
27770 this.hidden = false;
27772 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27780 this.hidden = true;
27782 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27787 * Convenience function for boolean show/hide
27788 * @param {Boolean} visible True to show, false to hide
27790 setVisible: function(visible){
27799 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27800 * @param {Boolean} state (optional) Force a particular state
27802 toggle : function(state){
27803 state = state === undefined ? !this.pressed : state;
27804 if(state != this.pressed){
27806 this.el.addClass("x-btn-pressed");
27807 this.pressed = true;
27808 this.fireEvent("toggle", this, true);
27810 this.el.removeClass("x-btn-pressed");
27811 this.pressed = false;
27812 this.fireEvent("toggle", this, false);
27814 if(this.toggleHandler){
27815 this.toggleHandler.call(this.scope || this, this, state);
27823 focus : function(){
27824 this.el.child('button:first').focus();
27828 * Disable this button
27830 disable : function(){
27832 this.el.addClass("x-btn-disabled");
27834 this.disabled = true;
27838 * Enable this button
27840 enable : function(){
27842 this.el.removeClass("x-btn-disabled");
27844 this.disabled = false;
27848 * Convenience function for boolean enable/disable
27849 * @param {Boolean} enabled True to enable, false to disable
27851 setDisabled : function(v){
27852 this[v !== true ? "enable" : "disable"]();
27856 onClick : function(e){
27858 e.preventDefault();
27863 if(!this.disabled){
27864 if(this.enableToggle){
27867 if(this.menu && !this.menu.isVisible()){
27868 this.menu.show(this.el, this.menuAlign);
27870 this.fireEvent("click", this, e);
27872 this.el.removeClass("x-btn-over");
27873 this.handler.call(this.scope || this, this, e);
27878 onMouseOver : function(e){
27879 if(!this.disabled){
27880 this.el.addClass("x-btn-over");
27881 this.fireEvent('mouseover', this, e);
27885 onMouseOut : function(e){
27886 if(!e.within(this.el, true)){
27887 this.el.removeClass("x-btn-over");
27888 this.fireEvent('mouseout', this, e);
27892 onFocus : function(e){
27893 if(!this.disabled){
27894 this.el.addClass("x-btn-focus");
27898 onBlur : function(e){
27899 this.el.removeClass("x-btn-focus");
27902 onMouseDown : function(e){
27903 if(!this.disabled && e.button == 0){
27904 this.el.addClass("x-btn-click");
27905 Roo.get(document).on('mouseup', this.onMouseUp, this);
27909 onMouseUp : function(e){
27911 this.el.removeClass("x-btn-click");
27912 Roo.get(document).un('mouseup', this.onMouseUp, this);
27916 onMenuShow : function(e){
27917 this.el.addClass("x-btn-menu-active");
27920 onMenuHide : function(e){
27921 this.el.removeClass("x-btn-menu-active");
27925 // Private utility class used by Button
27926 Roo.ButtonToggleMgr = function(){
27929 function toggleGroup(btn, state){
27931 var g = groups[btn.toggleGroup];
27932 for(var i = 0, l = g.length; i < l; i++){
27934 g[i].toggle(false);
27941 register : function(btn){
27942 if(!btn.toggleGroup){
27945 var g = groups[btn.toggleGroup];
27947 g = groups[btn.toggleGroup] = [];
27950 btn.on("toggle", toggleGroup);
27953 unregister : function(btn){
27954 if(!btn.toggleGroup){
27957 var g = groups[btn.toggleGroup];
27960 btn.un("toggle", toggleGroup);
27966 * Ext JS Library 1.1.1
27967 * Copyright(c) 2006-2007, Ext JS, LLC.
27969 * Originally Released Under LGPL - original licence link has changed is not relivant.
27972 * <script type="text/javascript">
27976 * @class Roo.SplitButton
27977 * @extends Roo.Button
27978 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27979 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27980 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27981 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27982 * @cfg {String} arrowTooltip The title attribute of the arrow
27984 * Create a new menu button
27985 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27986 * @param {Object} config The config object
27988 Roo.SplitButton = function(renderTo, config){
27989 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27991 * @event arrowclick
27992 * Fires when this button's arrow is clicked
27993 * @param {SplitButton} this
27994 * @param {EventObject} e The click event
27996 this.addEvents({"arrowclick":true});
27999 Roo.extend(Roo.SplitButton, Roo.Button, {
28000 render : function(renderTo){
28001 // this is one sweet looking template!
28002 var tpl = new Roo.Template(
28003 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
28004 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
28005 '<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>',
28006 "</tbody></table></td><td>",
28007 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
28008 '<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>',
28009 "</tbody></table></td></tr></table>"
28011 var btn = tpl.append(renderTo, [this.text, this.type], true);
28012 var btnEl = btn.child("button");
28014 btn.addClass(this.cls);
28017 btnEl.setStyle('background-image', 'url(' +this.icon +')');
28020 btnEl.addClass(this.iconCls);
28022 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
28026 if(this.handleMouseEvents){
28027 btn.on("mouseover", this.onMouseOver, this);
28028 btn.on("mouseout", this.onMouseOut, this);
28029 btn.on("mousedown", this.onMouseDown, this);
28030 btn.on("mouseup", this.onMouseUp, this);
28032 btn.on(this.clickEvent, this.onClick, this);
28034 if(typeof this.tooltip == 'object'){
28035 Roo.QuickTips.tips(Roo.apply({
28039 btnEl.dom[this.tooltipType] = this.tooltip;
28042 if(this.arrowTooltip){
28043 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
28052 this.el.addClass("x-btn-pressed");
28054 if(Roo.isIE && !Roo.isIE7){
28055 this.autoWidth.defer(1, this);
28060 this.menu.on("show", this.onMenuShow, this);
28061 this.menu.on("hide", this.onMenuHide, this);
28063 this.fireEvent('render', this);
28067 autoWidth : function(){
28069 var tbl = this.el.child("table:first");
28070 var tbl2 = this.el.child("table:last");
28071 this.el.setWidth("auto");
28072 tbl.setWidth("auto");
28073 if(Roo.isIE7 && Roo.isStrict){
28074 var ib = this.el.child('button:first');
28075 if(ib && ib.getWidth() > 20){
28077 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28082 this.el.beginMeasure();
28084 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28085 tbl.setWidth(this.minWidth-tbl2.getWidth());
28088 this.el.endMeasure();
28091 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28095 * Sets this button's click handler
28096 * @param {Function} handler The function to call when the button is clicked
28097 * @param {Object} scope (optional) Scope for the function passed above
28099 setHandler : function(handler, scope){
28100 this.handler = handler;
28101 this.scope = scope;
28105 * Sets this button's arrow click handler
28106 * @param {Function} handler The function to call when the arrow is clicked
28107 * @param {Object} scope (optional) Scope for the function passed above
28109 setArrowHandler : function(handler, scope){
28110 this.arrowHandler = handler;
28111 this.scope = scope;
28117 focus : function(){
28119 this.el.child("button:first").focus();
28124 onClick : function(e){
28125 e.preventDefault();
28126 if(!this.disabled){
28127 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28128 if(this.menu && !this.menu.isVisible()){
28129 this.menu.show(this.el, this.menuAlign);
28131 this.fireEvent("arrowclick", this, e);
28132 if(this.arrowHandler){
28133 this.arrowHandler.call(this.scope || this, this, e);
28136 this.fireEvent("click", this, e);
28138 this.handler.call(this.scope || this, this, e);
28144 onMouseDown : function(e){
28145 if(!this.disabled){
28146 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28150 onMouseUp : function(e){
28151 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28156 // backwards compat
28157 Roo.MenuButton = Roo.SplitButton;/*
28159 * Ext JS Library 1.1.1
28160 * Copyright(c) 2006-2007, Ext JS, LLC.
28162 * Originally Released Under LGPL - original licence link has changed is not relivant.
28165 * <script type="text/javascript">
28169 * @class Roo.Toolbar
28170 * Basic Toolbar class.
28172 * Creates a new Toolbar
28173 * @param {Object} container The config object
28175 Roo.Toolbar = function(container, buttons, config)
28177 /// old consturctor format still supported..
28178 if(container instanceof Array){ // omit the container for later rendering
28179 buttons = container;
28183 if (typeof(container) == 'object' && container.xtype) {
28184 config = container;
28185 container = config.container;
28186 buttons = config.buttons || []; // not really - use items!!
28189 if (config && config.items) {
28190 xitems = config.items;
28191 delete config.items;
28193 Roo.apply(this, config);
28194 this.buttons = buttons;
28197 this.render(container);
28199 this.xitems = xitems;
28200 Roo.each(xitems, function(b) {
28206 Roo.Toolbar.prototype = {
28208 * @cfg {Array} items
28209 * array of button configs or elements to add (will be converted to a MixedCollection)
28213 * @cfg {String/HTMLElement/Element} container
28214 * The id or element that will contain the toolbar
28217 render : function(ct){
28218 this.el = Roo.get(ct);
28220 this.el.addClass(this.cls);
28222 // using a table allows for vertical alignment
28223 // 100% width is needed by Safari...
28224 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28225 this.tr = this.el.child("tr", true);
28227 this.items = new Roo.util.MixedCollection(false, function(o){
28228 return o.id || ("item" + (++autoId));
28231 this.add.apply(this, this.buttons);
28232 delete this.buttons;
28237 * Adds element(s) to the toolbar -- this function takes a variable number of
28238 * arguments of mixed type and adds them to the toolbar.
28239 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28241 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28242 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28243 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28244 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28245 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28246 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28247 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28248 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28249 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28251 * @param {Mixed} arg2
28252 * @param {Mixed} etc.
28255 var a = arguments, l = a.length;
28256 for(var i = 0; i < l; i++){
28261 _add : function(el) {
28264 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28267 if (el.applyTo){ // some kind of form field
28268 return this.addField(el);
28270 if (el.render){ // some kind of Toolbar.Item
28271 return this.addItem(el);
28273 if (typeof el == "string"){ // string
28274 if(el == "separator" || el == "-"){
28275 return this.addSeparator();
28278 return this.addSpacer();
28281 return this.addFill();
28283 return this.addText(el);
28286 if(el.tagName){ // element
28287 return this.addElement(el);
28289 if(typeof el == "object"){ // must be button config?
28290 return this.addButton(el);
28292 // and now what?!?!
28298 * Add an Xtype element
28299 * @param {Object} xtype Xtype Object
28300 * @return {Object} created Object
28302 addxtype : function(e){
28303 return this.add(e);
28307 * Returns the Element for this toolbar.
28308 * @return {Roo.Element}
28310 getEl : function(){
28316 * @return {Roo.Toolbar.Item} The separator item
28318 addSeparator : function(){
28319 return this.addItem(new Roo.Toolbar.Separator());
28323 * Adds a spacer element
28324 * @return {Roo.Toolbar.Spacer} The spacer item
28326 addSpacer : function(){
28327 return this.addItem(new Roo.Toolbar.Spacer());
28331 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28332 * @return {Roo.Toolbar.Fill} The fill item
28334 addFill : function(){
28335 return this.addItem(new Roo.Toolbar.Fill());
28339 * Adds any standard HTML element to the toolbar
28340 * @param {String/HTMLElement/Element} el The element or id of the element to add
28341 * @return {Roo.Toolbar.Item} The element's item
28343 addElement : function(el){
28344 return this.addItem(new Roo.Toolbar.Item(el));
28347 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28348 * @type Roo.util.MixedCollection
28353 * Adds any Toolbar.Item or subclass
28354 * @param {Roo.Toolbar.Item} item
28355 * @return {Roo.Toolbar.Item} The item
28357 addItem : function(item){
28358 var td = this.nextBlock();
28360 this.items.add(item);
28365 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28366 * @param {Object/Array} config A button config or array of configs
28367 * @return {Roo.Toolbar.Button/Array}
28369 addButton : function(config){
28370 if(config instanceof Array){
28372 for(var i = 0, len = config.length; i < len; i++) {
28373 buttons.push(this.addButton(config[i]));
28378 if(!(config instanceof Roo.Toolbar.Button)){
28380 new Roo.Toolbar.SplitButton(config) :
28381 new Roo.Toolbar.Button(config);
28383 var td = this.nextBlock();
28390 * Adds text to the toolbar
28391 * @param {String} text The text to add
28392 * @return {Roo.Toolbar.Item} The element's item
28394 addText : function(text){
28395 return this.addItem(new Roo.Toolbar.TextItem(text));
28399 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28400 * @param {Number} index The index where the item is to be inserted
28401 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28402 * @return {Roo.Toolbar.Button/Item}
28404 insertButton : function(index, item){
28405 if(item instanceof Array){
28407 for(var i = 0, len = item.length; i < len; i++) {
28408 buttons.push(this.insertButton(index + i, item[i]));
28412 if (!(item instanceof Roo.Toolbar.Button)){
28413 item = new Roo.Toolbar.Button(item);
28415 var td = document.createElement("td");
28416 this.tr.insertBefore(td, this.tr.childNodes[index]);
28418 this.items.insert(index, item);
28423 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28424 * @param {Object} config
28425 * @return {Roo.Toolbar.Item} The element's item
28427 addDom : function(config, returnEl){
28428 var td = this.nextBlock();
28429 Roo.DomHelper.overwrite(td, config);
28430 var ti = new Roo.Toolbar.Item(td.firstChild);
28432 this.items.add(ti);
28437 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28438 * @type Roo.util.MixedCollection
28443 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28444 * Note: the field should not have been rendered yet. For a field that has already been
28445 * rendered, use {@link #addElement}.
28446 * @param {Roo.form.Field} field
28447 * @return {Roo.ToolbarItem}
28451 addField : function(field) {
28452 if (!this.fields) {
28454 this.fields = new Roo.util.MixedCollection(false, function(o){
28455 return o.id || ("item" + (++autoId));
28460 var td = this.nextBlock();
28462 var ti = new Roo.Toolbar.Item(td.firstChild);
28464 this.items.add(ti);
28465 this.fields.add(field);
28476 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28477 this.el.child('div').hide();
28485 this.el.child('div').show();
28489 nextBlock : function(){
28490 var td = document.createElement("td");
28491 this.tr.appendChild(td);
28496 destroy : function(){
28497 if(this.items){ // rendered?
28498 Roo.destroy.apply(Roo, this.items.items);
28500 if(this.fields){ // rendered?
28501 Roo.destroy.apply(Roo, this.fields.items);
28503 Roo.Element.uncache(this.el, this.tr);
28508 * @class Roo.Toolbar.Item
28509 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28511 * Creates a new Item
28512 * @param {HTMLElement} el
28514 Roo.Toolbar.Item = function(el){
28515 this.el = Roo.getDom(el);
28516 this.id = Roo.id(this.el);
28517 this.hidden = false;
28520 Roo.Toolbar.Item.prototype = {
28523 * Get this item's HTML Element
28524 * @return {HTMLElement}
28526 getEl : function(){
28531 render : function(td){
28533 td.appendChild(this.el);
28537 * Removes and destroys this item.
28539 destroy : function(){
28540 this.td.parentNode.removeChild(this.td);
28547 this.hidden = false;
28548 this.td.style.display = "";
28555 this.hidden = true;
28556 this.td.style.display = "none";
28560 * Convenience function for boolean show/hide.
28561 * @param {Boolean} visible true to show/false to hide
28563 setVisible: function(visible){
28572 * Try to focus this item.
28574 focus : function(){
28575 Roo.fly(this.el).focus();
28579 * Disables this item.
28581 disable : function(){
28582 Roo.fly(this.td).addClass("x-item-disabled");
28583 this.disabled = true;
28584 this.el.disabled = true;
28588 * Enables this item.
28590 enable : function(){
28591 Roo.fly(this.td).removeClass("x-item-disabled");
28592 this.disabled = false;
28593 this.el.disabled = false;
28599 * @class Roo.Toolbar.Separator
28600 * @extends Roo.Toolbar.Item
28601 * A simple toolbar separator class
28603 * Creates a new Separator
28605 Roo.Toolbar.Separator = function(){
28606 var s = document.createElement("span");
28607 s.className = "ytb-sep";
28608 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
28610 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28611 enable:Roo.emptyFn,
28612 disable:Roo.emptyFn,
28617 * @class Roo.Toolbar.Spacer
28618 * @extends Roo.Toolbar.Item
28619 * A simple element that adds extra horizontal space to a toolbar.
28621 * Creates a new Spacer
28623 Roo.Toolbar.Spacer = function(){
28624 var s = document.createElement("div");
28625 s.className = "ytb-spacer";
28626 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
28628 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28629 enable:Roo.emptyFn,
28630 disable:Roo.emptyFn,
28635 * @class Roo.Toolbar.Fill
28636 * @extends Roo.Toolbar.Spacer
28637 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28639 * Creates a new Spacer
28641 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28643 render : function(td){
28644 td.style.width = '100%';
28645 Roo.Toolbar.Fill.superclass.render.call(this, td);
28650 * @class Roo.Toolbar.TextItem
28651 * @extends Roo.Toolbar.Item
28652 * A simple class that renders text directly into a toolbar.
28654 * Creates a new TextItem
28655 * @param {String} text
28657 Roo.Toolbar.TextItem = function(text){
28658 if (typeof(text) == 'object') {
28661 var s = document.createElement("span");
28662 s.className = "ytb-text";
28663 s.innerHTML = text;
28664 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28666 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28667 enable:Roo.emptyFn,
28668 disable:Roo.emptyFn,
28673 * @class Roo.Toolbar.Button
28674 * @extends Roo.Button
28675 * A button that renders into a toolbar.
28677 * Creates a new Button
28678 * @param {Object} config A standard {@link Roo.Button} config object
28680 Roo.Toolbar.Button = function(config){
28681 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28683 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28684 render : function(td){
28686 Roo.Toolbar.Button.superclass.render.call(this, td);
28690 * Removes and destroys this button
28692 destroy : function(){
28693 Roo.Toolbar.Button.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 * Disables this item
28716 disable : function(){
28717 Roo.fly(this.td).addClass("x-item-disabled");
28718 this.disabled = true;
28722 * Enables this item
28724 enable : function(){
28725 Roo.fly(this.td).removeClass("x-item-disabled");
28726 this.disabled = false;
28729 // backwards compat
28730 Roo.ToolbarButton = Roo.Toolbar.Button;
28733 * @class Roo.Toolbar.SplitButton
28734 * @extends Roo.SplitButton
28735 * A menu button that renders into a toolbar.
28737 * Creates a new SplitButton
28738 * @param {Object} config A standard {@link Roo.SplitButton} config object
28740 Roo.Toolbar.SplitButton = function(config){
28741 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28743 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28744 render : function(td){
28746 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28750 * Removes and destroys this button
28752 destroy : function(){
28753 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28754 this.td.parentNode.removeChild(this.td);
28758 * Shows this button
28761 this.hidden = false;
28762 this.td.style.display = "";
28766 * Hides this button
28769 this.hidden = true;
28770 this.td.style.display = "none";
28774 // backwards compat
28775 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28777 * Ext JS Library 1.1.1
28778 * Copyright(c) 2006-2007, Ext JS, LLC.
28780 * Originally Released Under LGPL - original licence link has changed is not relivant.
28783 * <script type="text/javascript">
28787 * @class Roo.PagingToolbar
28788 * @extends Roo.Toolbar
28789 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28791 * Create a new PagingToolbar
28792 * @param {Object} config The config object
28794 Roo.PagingToolbar = function(el, ds, config)
28796 // old args format still supported... - xtype is prefered..
28797 if (typeof(el) == 'object' && el.xtype) {
28798 // created from xtype...
28800 ds = el.dataSource;
28801 el = config.container;
28804 if (config.items) {
28805 items = config.items;
28809 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28812 this.renderButtons(this.el);
28815 // supprot items array.
28817 Roo.each(items, function(e) {
28818 this.add(Roo.factory(e));
28823 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28825 * @cfg {Roo.data.Store} dataSource
28826 * The underlying data store providing the paged data
28829 * @cfg {String/HTMLElement/Element} container
28830 * container The id or element that will contain the toolbar
28833 * @cfg {Boolean} displayInfo
28834 * True to display the displayMsg (defaults to false)
28837 * @cfg {Number} pageSize
28838 * The number of records to display per page (defaults to 20)
28842 * @cfg {String} displayMsg
28843 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28845 displayMsg : 'Displaying {0} - {1} of {2}',
28847 * @cfg {String} emptyMsg
28848 * The message to display when no records are found (defaults to "No data to display")
28850 emptyMsg : 'No data to display',
28852 * Customizable piece of the default paging text (defaults to "Page")
28855 beforePageText : "Page",
28857 * Customizable piece of the default paging text (defaults to "of %0")
28860 afterPageText : "of {0}",
28862 * Customizable piece of the default paging text (defaults to "First Page")
28865 firstText : "First Page",
28867 * Customizable piece of the default paging text (defaults to "Previous Page")
28870 prevText : "Previous Page",
28872 * Customizable piece of the default paging text (defaults to "Next Page")
28875 nextText : "Next Page",
28877 * Customizable piece of the default paging text (defaults to "Last Page")
28880 lastText : "Last Page",
28882 * Customizable piece of the default paging text (defaults to "Refresh")
28885 refreshText : "Refresh",
28888 renderButtons : function(el){
28889 Roo.PagingToolbar.superclass.render.call(this, el);
28890 this.first = this.addButton({
28891 tooltip: this.firstText,
28892 cls: "x-btn-icon x-grid-page-first",
28894 handler: this.onClick.createDelegate(this, ["first"])
28896 this.prev = this.addButton({
28897 tooltip: this.prevText,
28898 cls: "x-btn-icon x-grid-page-prev",
28900 handler: this.onClick.createDelegate(this, ["prev"])
28902 //this.addSeparator();
28903 this.add(this.beforePageText);
28904 this.field = Roo.get(this.addDom({
28909 cls: "x-grid-page-number"
28911 this.field.on("keydown", this.onPagingKeydown, this);
28912 this.field.on("focus", function(){this.dom.select();});
28913 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28914 this.field.setHeight(18);
28915 //this.addSeparator();
28916 this.next = this.addButton({
28917 tooltip: this.nextText,
28918 cls: "x-btn-icon x-grid-page-next",
28920 handler: this.onClick.createDelegate(this, ["next"])
28922 this.last = this.addButton({
28923 tooltip: this.lastText,
28924 cls: "x-btn-icon x-grid-page-last",
28926 handler: this.onClick.createDelegate(this, ["last"])
28928 //this.addSeparator();
28929 this.loading = this.addButton({
28930 tooltip: this.refreshText,
28931 cls: "x-btn-icon x-grid-loading",
28932 handler: this.onClick.createDelegate(this, ["refresh"])
28935 if(this.displayInfo){
28936 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28941 updateInfo : function(){
28942 if(this.displayEl){
28943 var count = this.ds.getCount();
28944 var msg = count == 0 ?
28948 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28950 this.displayEl.update(msg);
28955 onLoad : function(ds, r, o){
28956 this.cursor = o.params ? o.params.start : 0;
28957 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28959 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28960 this.field.dom.value = ap;
28961 this.first.setDisabled(ap == 1);
28962 this.prev.setDisabled(ap == 1);
28963 this.next.setDisabled(ap == ps);
28964 this.last.setDisabled(ap == ps);
28965 this.loading.enable();
28970 getPageData : function(){
28971 var total = this.ds.getTotalCount();
28974 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28975 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28980 onLoadError : function(){
28981 this.loading.enable();
28985 onPagingKeydown : function(e){
28986 var k = e.getKey();
28987 var d = this.getPageData();
28989 var v = this.field.dom.value, pageNum;
28990 if(!v || isNaN(pageNum = parseInt(v, 10))){
28991 this.field.dom.value = d.activePage;
28994 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28995 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28998 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))
29000 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
29001 this.field.dom.value = pageNum;
29002 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
29005 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29007 var v = this.field.dom.value, pageNum;
29008 var increment = (e.shiftKey) ? 10 : 1;
29009 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29011 if(!v || isNaN(pageNum = parseInt(v, 10))) {
29012 this.field.dom.value = d.activePage;
29015 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
29017 this.field.dom.value = parseInt(v, 10) + increment;
29018 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
29019 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29026 beforeLoad : function(){
29028 this.loading.disable();
29033 onClick : function(which){
29037 ds.load({params:{start: 0, limit: this.pageSize}});
29040 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
29043 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
29046 var total = ds.getTotalCount();
29047 var extra = total % this.pageSize;
29048 var lastStart = extra ? (total - extra) : total-this.pageSize;
29049 ds.load({params:{start: lastStart, limit: this.pageSize}});
29052 ds.load({params:{start: this.cursor, limit: this.pageSize}});
29058 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
29059 * @param {Roo.data.Store} store The data store to unbind
29061 unbind : function(ds){
29062 ds.un("beforeload", this.beforeLoad, this);
29063 ds.un("load", this.onLoad, this);
29064 ds.un("loadexception", this.onLoadError, this);
29065 ds.un("remove", this.updateInfo, this);
29066 ds.un("add", this.updateInfo, this);
29067 this.ds = undefined;
29071 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29072 * @param {Roo.data.Store} store The data store to bind
29074 bind : function(ds){
29075 ds.on("beforeload", this.beforeLoad, this);
29076 ds.on("load", this.onLoad, this);
29077 ds.on("loadexception", this.onLoadError, this);
29078 ds.on("remove", this.updateInfo, this);
29079 ds.on("add", this.updateInfo, this);
29084 * Ext JS Library 1.1.1
29085 * Copyright(c) 2006-2007, Ext JS, LLC.
29087 * Originally Released Under LGPL - original licence link has changed is not relivant.
29090 * <script type="text/javascript">
29094 * @class Roo.Resizable
29095 * @extends Roo.util.Observable
29096 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29097 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29098 * 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
29099 * the element will be wrapped for you automatically.</p>
29100 * <p>Here is the list of valid resize handles:</p>
29103 ------ -------------------
29112 'hd' horizontal drag
29115 * <p>Here's an example showing the creation of a typical Resizable:</p>
29117 var resizer = new Roo.Resizable("element-id", {
29125 resizer.on("resize", myHandler);
29127 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29128 * resizer.east.setDisplayed(false);</p>
29129 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29130 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29131 * resize operation's new size (defaults to [0, 0])
29132 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29133 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29134 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29135 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29136 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29137 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29138 * @cfg {Number} width The width of the element in pixels (defaults to null)
29139 * @cfg {Number} height The height of the element in pixels (defaults to null)
29140 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29141 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29142 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29143 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29144 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29145 * in favor of the handles config option (defaults to false)
29146 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29147 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29148 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29149 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29150 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29151 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29152 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29153 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29154 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29155 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29156 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29158 * Create a new resizable component
29159 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29160 * @param {Object} config configuration options
29162 Roo.Resizable = function(el, config)
29164 this.el = Roo.get(el);
29166 if(config && config.wrap){
29167 config.resizeChild = this.el;
29168 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29169 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29170 this.el.setStyle("overflow", "hidden");
29171 this.el.setPositioning(config.resizeChild.getPositioning());
29172 config.resizeChild.clearPositioning();
29173 if(!config.width || !config.height){
29174 var csize = config.resizeChild.getSize();
29175 this.el.setSize(csize.width, csize.height);
29177 if(config.pinned && !config.adjustments){
29178 config.adjustments = "auto";
29182 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29183 this.proxy.unselectable();
29184 this.proxy.enableDisplayMode('block');
29186 Roo.apply(this, config);
29189 this.disableTrackOver = true;
29190 this.el.addClass("x-resizable-pinned");
29192 // if the element isn't positioned, make it relative
29193 var position = this.el.getStyle("position");
29194 if(position != "absolute" && position != "fixed"){
29195 this.el.setStyle("position", "relative");
29197 if(!this.handles){ // no handles passed, must be legacy style
29198 this.handles = 's,e,se';
29199 if(this.multiDirectional){
29200 this.handles += ',n,w';
29203 if(this.handles == "all"){
29204 this.handles = "n s e w ne nw se sw";
29206 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29207 var ps = Roo.Resizable.positions;
29208 for(var i = 0, len = hs.length; i < len; i++){
29209 if(hs[i] && ps[hs[i]]){
29210 var pos = ps[hs[i]];
29211 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29215 this.corner = this.southeast;
29217 // updateBox = the box can move..
29218 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29219 this.updateBox = true;
29222 this.activeHandle = null;
29224 if(this.resizeChild){
29225 if(typeof this.resizeChild == "boolean"){
29226 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29228 this.resizeChild = Roo.get(this.resizeChild, true);
29232 if(this.adjustments == "auto"){
29233 var rc = this.resizeChild;
29234 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29235 if(rc && (hw || hn)){
29236 rc.position("relative");
29237 rc.setLeft(hw ? hw.el.getWidth() : 0);
29238 rc.setTop(hn ? hn.el.getHeight() : 0);
29240 this.adjustments = [
29241 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29242 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29246 if(this.draggable){
29247 this.dd = this.dynamic ?
29248 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29249 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29255 * @event beforeresize
29256 * Fired before resize is allowed. Set enabled to false to cancel resize.
29257 * @param {Roo.Resizable} this
29258 * @param {Roo.EventObject} e The mousedown event
29260 "beforeresize" : true,
29263 * Fired a resizing.
29264 * @param {Roo.Resizable} this
29265 * @param {Number} x The new x position
29266 * @param {Number} y The new y position
29267 * @param {Number} w The new w width
29268 * @param {Number} h The new h hight
29269 * @param {Roo.EventObject} e The mouseup event
29274 * Fired after a resize.
29275 * @param {Roo.Resizable} this
29276 * @param {Number} width The new width
29277 * @param {Number} height The new height
29278 * @param {Roo.EventObject} e The mouseup event
29283 if(this.width !== null && this.height !== null){
29284 this.resizeTo(this.width, this.height);
29286 this.updateChildSize();
29289 this.el.dom.style.zoom = 1;
29291 Roo.Resizable.superclass.constructor.call(this);
29294 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29295 resizeChild : false,
29296 adjustments : [0, 0],
29306 multiDirectional : false,
29307 disableTrackOver : false,
29308 easing : 'easeOutStrong',
29309 widthIncrement : 0,
29310 heightIncrement : 0,
29314 preserveRatio : false,
29315 transparent: false,
29321 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29323 constrainTo: undefined,
29325 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29327 resizeRegion: undefined,
29331 * Perform a manual resize
29332 * @param {Number} width
29333 * @param {Number} height
29335 resizeTo : function(width, height){
29336 this.el.setSize(width, height);
29337 this.updateChildSize();
29338 this.fireEvent("resize", this, width, height, null);
29342 startSizing : function(e, handle){
29343 this.fireEvent("beforeresize", this, e);
29344 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29347 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29348 this.overlay.unselectable();
29349 this.overlay.enableDisplayMode("block");
29350 this.overlay.on("mousemove", this.onMouseMove, this);
29351 this.overlay.on("mouseup", this.onMouseUp, this);
29353 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29355 this.resizing = true;
29356 this.startBox = this.el.getBox();
29357 this.startPoint = e.getXY();
29358 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29359 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29361 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29362 this.overlay.show();
29364 if(this.constrainTo) {
29365 var ct = Roo.get(this.constrainTo);
29366 this.resizeRegion = ct.getRegion().adjust(
29367 ct.getFrameWidth('t'),
29368 ct.getFrameWidth('l'),
29369 -ct.getFrameWidth('b'),
29370 -ct.getFrameWidth('r')
29374 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29376 this.proxy.setBox(this.startBox);
29378 this.proxy.setStyle('visibility', 'visible');
29384 onMouseDown : function(handle, e){
29387 this.activeHandle = handle;
29388 this.startSizing(e, handle);
29393 onMouseUp : function(e){
29394 var size = this.resizeElement();
29395 this.resizing = false;
29397 this.overlay.hide();
29399 this.fireEvent("resize", this, size.width, size.height, e);
29403 updateChildSize : function(){
29405 if(this.resizeChild){
29407 var child = this.resizeChild;
29408 var adj = this.adjustments;
29409 if(el.dom.offsetWidth){
29410 var b = el.getSize(true);
29411 child.setSize(b.width+adj[0], b.height+adj[1]);
29413 // Second call here for IE
29414 // The first call enables instant resizing and
29415 // the second call corrects scroll bars if they
29418 setTimeout(function(){
29419 if(el.dom.offsetWidth){
29420 var b = el.getSize(true);
29421 child.setSize(b.width+adj[0], b.height+adj[1]);
29429 snap : function(value, inc, min){
29430 if(!inc || !value) return value;
29431 var newValue = value;
29432 var m = value % inc;
29435 newValue = value + (inc-m);
29437 newValue = value - m;
29440 return Math.max(min, newValue);
29444 resizeElement : function(){
29445 var box = this.proxy.getBox();
29446 if(this.updateBox){
29447 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29449 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29451 this.updateChildSize();
29459 constrain : function(v, diff, m, mx){
29462 }else if(v - diff > mx){
29469 onMouseMove : function(e){
29472 try{// try catch so if something goes wrong the user doesn't get hung
29474 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29478 //var curXY = this.startPoint;
29479 var curSize = this.curSize || this.startBox;
29480 var x = this.startBox.x, y = this.startBox.y;
29481 var ox = x, oy = y;
29482 var w = curSize.width, h = curSize.height;
29483 var ow = w, oh = h;
29484 var mw = this.minWidth, mh = this.minHeight;
29485 var mxw = this.maxWidth, mxh = this.maxHeight;
29486 var wi = this.widthIncrement;
29487 var hi = this.heightIncrement;
29489 var eventXY = e.getXY();
29490 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29491 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29493 var pos = this.activeHandle.position;
29498 w = Math.min(Math.max(mw, w), mxw);
29503 h = Math.min(Math.max(mh, h), mxh);
29508 w = Math.min(Math.max(mw, w), mxw);
29509 h = Math.min(Math.max(mh, h), mxh);
29512 diffY = this.constrain(h, diffY, mh, mxh);
29519 var adiffX = Math.abs(diffX);
29520 var sub = (adiffX % wi); // how much
29521 if (sub > (wi/2)) { // far enough to snap
29522 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29524 // remove difference..
29525 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29529 x = Math.max(this.minX, x);
29532 diffX = this.constrain(w, diffX, mw, mxw);
29538 w = Math.min(Math.max(mw, w), mxw);
29539 diffY = this.constrain(h, diffY, mh, mxh);
29544 diffX = this.constrain(w, diffX, mw, mxw);
29545 diffY = this.constrain(h, diffY, mh, mxh);
29552 diffX = this.constrain(w, diffX, mw, mxw);
29554 h = Math.min(Math.max(mh, h), mxh);
29560 var sw = this.snap(w, wi, mw);
29561 var sh = this.snap(h, hi, mh);
29562 if(sw != w || sh != h){
29585 if(this.preserveRatio){
29590 h = Math.min(Math.max(mh, h), mxh);
29595 w = Math.min(Math.max(mw, w), mxw);
29600 w = Math.min(Math.max(mw, w), mxw);
29606 w = Math.min(Math.max(mw, w), mxw);
29612 h = Math.min(Math.max(mh, h), mxh);
29620 h = Math.min(Math.max(mh, h), mxh);
29630 h = Math.min(Math.max(mh, h), mxh);
29638 if (pos == 'hdrag') {
29641 this.proxy.setBounds(x, y, w, h);
29643 this.resizeElement();
29647 this.fireEvent("resizing", this, x, y, w, h, e);
29651 handleOver : function(){
29653 this.el.addClass("x-resizable-over");
29658 handleOut : function(){
29659 if(!this.resizing){
29660 this.el.removeClass("x-resizable-over");
29665 * Returns the element this component is bound to.
29666 * @return {Roo.Element}
29668 getEl : function(){
29673 * Returns the resizeChild element (or null).
29674 * @return {Roo.Element}
29676 getResizeChild : function(){
29677 return this.resizeChild;
29679 groupHandler : function()
29684 * Destroys this resizable. If the element was wrapped and
29685 * removeEl is not true then the element remains.
29686 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29688 destroy : function(removeEl){
29689 this.proxy.remove();
29691 this.overlay.removeAllListeners();
29692 this.overlay.remove();
29694 var ps = Roo.Resizable.positions;
29696 if(typeof ps[k] != "function" && this[ps[k]]){
29697 var h = this[ps[k]];
29698 h.el.removeAllListeners();
29703 this.el.update("");
29710 // hash to map config positions to true positions
29711 Roo.Resizable.positions = {
29712 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29717 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29719 // only initialize the template if resizable is used
29720 var tpl = Roo.DomHelper.createTemplate(
29721 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29724 Roo.Resizable.Handle.prototype.tpl = tpl;
29726 this.position = pos;
29728 // show north drag fro topdra
29729 var handlepos = pos == 'hdrag' ? 'north' : pos;
29731 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29732 if (pos == 'hdrag') {
29733 this.el.setStyle('cursor', 'pointer');
29735 this.el.unselectable();
29737 this.el.setOpacity(0);
29739 this.el.on("mousedown", this.onMouseDown, this);
29740 if(!disableTrackOver){
29741 this.el.on("mouseover", this.onMouseOver, this);
29742 this.el.on("mouseout", this.onMouseOut, this);
29747 Roo.Resizable.Handle.prototype = {
29748 afterResize : function(rz){
29753 onMouseDown : function(e){
29754 this.rz.onMouseDown(this, e);
29757 onMouseOver : function(e){
29758 this.rz.handleOver(this, e);
29761 onMouseOut : function(e){
29762 this.rz.handleOut(this, e);
29766 * Ext JS Library 1.1.1
29767 * Copyright(c) 2006-2007, Ext JS, LLC.
29769 * Originally Released Under LGPL - original licence link has changed is not relivant.
29772 * <script type="text/javascript">
29776 * @class Roo.Editor
29777 * @extends Roo.Component
29778 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29780 * Create a new Editor
29781 * @param {Roo.form.Field} field The Field object (or descendant)
29782 * @param {Object} config The config object
29784 Roo.Editor = function(field, config){
29785 Roo.Editor.superclass.constructor.call(this, config);
29786 this.field = field;
29789 * @event beforestartedit
29790 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29791 * false from the handler of this event.
29792 * @param {Editor} this
29793 * @param {Roo.Element} boundEl The underlying element bound to this editor
29794 * @param {Mixed} value The field value being set
29796 "beforestartedit" : true,
29799 * Fires when this editor is displayed
29800 * @param {Roo.Element} boundEl The underlying element bound to this editor
29801 * @param {Mixed} value The starting field value
29803 "startedit" : true,
29805 * @event beforecomplete
29806 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29807 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29808 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29809 * event will not fire since no edit actually occurred.
29810 * @param {Editor} this
29811 * @param {Mixed} value The current field value
29812 * @param {Mixed} startValue The original field value
29814 "beforecomplete" : true,
29817 * Fires after editing is complete and any changed value has been written to the underlying field.
29818 * @param {Editor} this
29819 * @param {Mixed} value The current field value
29820 * @param {Mixed} startValue The original field value
29824 * @event specialkey
29825 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29826 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29827 * @param {Roo.form.Field} this
29828 * @param {Roo.EventObject} e The event object
29830 "specialkey" : true
29834 Roo.extend(Roo.Editor, Roo.Component, {
29836 * @cfg {Boolean/String} autosize
29837 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29838 * or "height" to adopt the height only (defaults to false)
29841 * @cfg {Boolean} revertInvalid
29842 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29843 * validation fails (defaults to true)
29846 * @cfg {Boolean} ignoreNoChange
29847 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29848 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29849 * will never be ignored.
29852 * @cfg {Boolean} hideEl
29853 * False to keep the bound element visible while the editor is displayed (defaults to true)
29856 * @cfg {Mixed} value
29857 * The data value of the underlying field (defaults to "")
29861 * @cfg {String} alignment
29862 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29866 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29867 * for bottom-right shadow (defaults to "frame")
29871 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29875 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29877 completeOnEnter : false,
29879 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29881 cancelOnEsc : false,
29883 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29888 onRender : function(ct, position){
29889 this.el = new Roo.Layer({
29890 shadow: this.shadow,
29896 constrain: this.constrain
29898 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29899 if(this.field.msgTarget != 'title'){
29900 this.field.msgTarget = 'qtip';
29902 this.field.render(this.el);
29904 this.field.el.dom.setAttribute('autocomplete', 'off');
29906 this.field.on("specialkey", this.onSpecialKey, this);
29907 if(this.swallowKeys){
29908 this.field.el.swallowEvent(['keydown','keypress']);
29911 this.field.on("blur", this.onBlur, this);
29912 if(this.field.grow){
29913 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29917 onSpecialKey : function(field, e)
29919 //Roo.log('editor onSpecialKey');
29920 if(this.completeOnEnter && e.getKey() == e.ENTER){
29922 this.completeEdit();
29925 // do not fire special key otherwise it might hide close the editor...
29926 if(e.getKey() == e.ENTER){
29929 if(this.cancelOnEsc && e.getKey() == e.ESC){
29933 this.fireEvent('specialkey', field, e);
29938 * Starts the editing process and shows the editor.
29939 * @param {String/HTMLElement/Element} el The element to edit
29940 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29941 * to the innerHTML of el.
29943 startEdit : function(el, value){
29945 this.completeEdit();
29947 this.boundEl = Roo.get(el);
29948 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29949 if(!this.rendered){
29950 this.render(this.parentEl || document.body);
29952 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29955 this.startValue = v;
29956 this.field.setValue(v);
29958 var sz = this.boundEl.getSize();
29959 switch(this.autoSize){
29961 this.setSize(sz.width, "");
29964 this.setSize("", sz.height);
29967 this.setSize(sz.width, sz.height);
29970 this.el.alignTo(this.boundEl, this.alignment);
29971 this.editing = true;
29973 Roo.QuickTips.disable();
29979 * Sets the height and width of this editor.
29980 * @param {Number} width The new width
29981 * @param {Number} height The new height
29983 setSize : function(w, h){
29984 this.field.setSize(w, h);
29991 * Realigns the editor to the bound field based on the current alignment config value.
29993 realign : function(){
29994 this.el.alignTo(this.boundEl, this.alignment);
29998 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29999 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
30001 completeEdit : function(remainVisible){
30005 var v = this.getValue();
30006 if(this.revertInvalid !== false && !this.field.isValid()){
30007 v = this.startValue;
30008 this.cancelEdit(true);
30010 if(String(v) === String(this.startValue) && this.ignoreNoChange){
30011 this.editing = false;
30015 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
30016 this.editing = false;
30017 if(this.updateEl && this.boundEl){
30018 this.boundEl.update(v);
30020 if(remainVisible !== true){
30023 this.fireEvent("complete", this, v, this.startValue);
30028 onShow : function(){
30030 if(this.hideEl !== false){
30031 this.boundEl.hide();
30034 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
30035 this.fixIEFocus = true;
30036 this.deferredFocus.defer(50, this);
30038 this.field.focus();
30040 this.fireEvent("startedit", this.boundEl, this.startValue);
30043 deferredFocus : function(){
30045 this.field.focus();
30050 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
30051 * reverted to the original starting value.
30052 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
30053 * cancel (defaults to false)
30055 cancelEdit : function(remainVisible){
30057 this.setValue(this.startValue);
30058 if(remainVisible !== true){
30065 onBlur : function(){
30066 if(this.allowBlur !== true && this.editing){
30067 this.completeEdit();
30072 onHide : function(){
30074 this.completeEdit();
30078 if(this.field.collapse){
30079 this.field.collapse();
30082 if(this.hideEl !== false){
30083 this.boundEl.show();
30086 Roo.QuickTips.enable();
30091 * Sets the data value of the editor
30092 * @param {Mixed} value Any valid value supported by the underlying field
30094 setValue : function(v){
30095 this.field.setValue(v);
30099 * Gets the data value of the editor
30100 * @return {Mixed} The data value
30102 getValue : function(){
30103 return this.field.getValue();
30107 * Ext JS Library 1.1.1
30108 * Copyright(c) 2006-2007, Ext JS, LLC.
30110 * Originally Released Under LGPL - original licence link has changed is not relivant.
30113 * <script type="text/javascript">
30117 * @class Roo.BasicDialog
30118 * @extends Roo.util.Observable
30119 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30121 var dlg = new Roo.BasicDialog("my-dlg", {
30130 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30131 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30132 dlg.addButton('Cancel', dlg.hide, dlg);
30135 <b>A Dialog should always be a direct child of the body element.</b>
30136 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30137 * @cfg {String} title Default text to display in the title bar (defaults to null)
30138 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30139 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30140 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30141 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30142 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30143 * (defaults to null with no animation)
30144 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30145 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30146 * property for valid values (defaults to 'all')
30147 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30148 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30149 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30150 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30151 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30152 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30153 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30154 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30155 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30156 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30157 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30158 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30159 * draggable = true (defaults to false)
30160 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30161 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30162 * shadow (defaults to false)
30163 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30164 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30165 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30166 * @cfg {Array} buttons Array of buttons
30167 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30169 * Create a new BasicDialog.
30170 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30171 * @param {Object} config Configuration options
30173 Roo.BasicDialog = function(el, config){
30174 this.el = Roo.get(el);
30175 var dh = Roo.DomHelper;
30176 if(!this.el && config && config.autoCreate){
30177 if(typeof config.autoCreate == "object"){
30178 if(!config.autoCreate.id){
30179 config.autoCreate.id = el;
30181 this.el = dh.append(document.body,
30182 config.autoCreate, true);
30184 this.el = dh.append(document.body,
30185 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30189 el.setDisplayed(true);
30190 el.hide = this.hideAction;
30192 el.addClass("x-dlg");
30194 Roo.apply(this, config);
30196 this.proxy = el.createProxy("x-dlg-proxy");
30197 this.proxy.hide = this.hideAction;
30198 this.proxy.setOpacity(.5);
30202 el.setWidth(config.width);
30205 el.setHeight(config.height);
30207 this.size = el.getSize();
30208 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30209 this.xy = [config.x,config.y];
30211 this.xy = el.getCenterXY(true);
30213 /** The header element @type Roo.Element */
30214 this.header = el.child("> .x-dlg-hd");
30215 /** The body element @type Roo.Element */
30216 this.body = el.child("> .x-dlg-bd");
30217 /** The footer element @type Roo.Element */
30218 this.footer = el.child("> .x-dlg-ft");
30221 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30224 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30227 this.header.unselectable();
30229 this.header.update(this.title);
30231 // this element allows the dialog to be focused for keyboard event
30232 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30233 this.focusEl.swallowEvent("click", true);
30235 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30237 // wrap the body and footer for special rendering
30238 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30240 this.bwrap.dom.appendChild(this.footer.dom);
30243 this.bg = this.el.createChild({
30244 tag: "div", cls:"x-dlg-bg",
30245 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30247 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30250 if(this.autoScroll !== false && !this.autoTabs){
30251 this.body.setStyle("overflow", "auto");
30254 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30256 if(this.closable !== false){
30257 this.el.addClass("x-dlg-closable");
30258 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30259 this.close.on("click", this.closeClick, this);
30260 this.close.addClassOnOver("x-dlg-close-over");
30262 if(this.collapsible !== false){
30263 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30264 this.collapseBtn.on("click", this.collapseClick, this);
30265 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30266 this.header.on("dblclick", this.collapseClick, this);
30268 if(this.resizable !== false){
30269 this.el.addClass("x-dlg-resizable");
30270 this.resizer = new Roo.Resizable(el, {
30271 minWidth: this.minWidth || 80,
30272 minHeight:this.minHeight || 80,
30273 handles: this.resizeHandles || "all",
30276 this.resizer.on("beforeresize", this.beforeResize, this);
30277 this.resizer.on("resize", this.onResize, this);
30279 if(this.draggable !== false){
30280 el.addClass("x-dlg-draggable");
30281 if (!this.proxyDrag) {
30282 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30285 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30287 dd.setHandleElId(this.header.id);
30288 dd.endDrag = this.endMove.createDelegate(this);
30289 dd.startDrag = this.startMove.createDelegate(this);
30290 dd.onDrag = this.onDrag.createDelegate(this);
30295 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30296 this.mask.enableDisplayMode("block");
30298 this.el.addClass("x-dlg-modal");
30301 this.shadow = new Roo.Shadow({
30302 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30303 offset : this.shadowOffset
30306 this.shadowOffset = 0;
30308 if(Roo.useShims && this.shim !== false){
30309 this.shim = this.el.createShim();
30310 this.shim.hide = this.hideAction;
30318 if (this.buttons) {
30319 var bts= this.buttons;
30321 Roo.each(bts, function(b) {
30330 * Fires when a key is pressed
30331 * @param {Roo.BasicDialog} this
30332 * @param {Roo.EventObject} e
30337 * Fires when this dialog is moved by the user.
30338 * @param {Roo.BasicDialog} this
30339 * @param {Number} x The new page X
30340 * @param {Number} y The new page Y
30345 * Fires when this dialog is resized by the user.
30346 * @param {Roo.BasicDialog} this
30347 * @param {Number} width The new width
30348 * @param {Number} height The new height
30352 * @event beforehide
30353 * Fires before this dialog is hidden.
30354 * @param {Roo.BasicDialog} this
30356 "beforehide" : true,
30359 * Fires when this dialog is hidden.
30360 * @param {Roo.BasicDialog} this
30364 * @event beforeshow
30365 * Fires before this dialog is shown.
30366 * @param {Roo.BasicDialog} this
30368 "beforeshow" : true,
30371 * Fires when this dialog is shown.
30372 * @param {Roo.BasicDialog} this
30376 el.on("keydown", this.onKeyDown, this);
30377 el.on("mousedown", this.toFront, this);
30378 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30380 Roo.DialogManager.register(this);
30381 Roo.BasicDialog.superclass.constructor.call(this);
30384 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30385 shadowOffset: Roo.isIE ? 6 : 5,
30388 minButtonWidth: 75,
30389 defaultButton: null,
30390 buttonAlign: "right",
30395 * Sets the dialog title text
30396 * @param {String} text The title text to display
30397 * @return {Roo.BasicDialog} this
30399 setTitle : function(text){
30400 this.header.update(text);
30405 closeClick : function(){
30410 collapseClick : function(){
30411 this[this.collapsed ? "expand" : "collapse"]();
30415 * Collapses the dialog to its minimized state (only the title bar is visible).
30416 * Equivalent to the user clicking the collapse dialog button.
30418 collapse : function(){
30419 if(!this.collapsed){
30420 this.collapsed = true;
30421 this.el.addClass("x-dlg-collapsed");
30422 this.restoreHeight = this.el.getHeight();
30423 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30428 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30429 * clicking the expand dialog button.
30431 expand : function(){
30432 if(this.collapsed){
30433 this.collapsed = false;
30434 this.el.removeClass("x-dlg-collapsed");
30435 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30440 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30441 * @return {Roo.TabPanel} The tabs component
30443 initTabs : function(){
30444 var tabs = this.getTabs();
30445 while(tabs.getTab(0)){
30448 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30450 tabs.addTab(Roo.id(dom), dom.title);
30458 beforeResize : function(){
30459 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30463 onResize : function(){
30464 this.refreshSize();
30465 this.syncBodyHeight();
30466 this.adjustAssets();
30468 this.fireEvent("resize", this, this.size.width, this.size.height);
30472 onKeyDown : function(e){
30473 if(this.isVisible()){
30474 this.fireEvent("keydown", this, e);
30479 * Resizes the dialog.
30480 * @param {Number} width
30481 * @param {Number} height
30482 * @return {Roo.BasicDialog} this
30484 resizeTo : function(width, height){
30485 this.el.setSize(width, height);
30486 this.size = {width: width, height: height};
30487 this.syncBodyHeight();
30488 if(this.fixedcenter){
30491 if(this.isVisible()){
30492 this.constrainXY();
30493 this.adjustAssets();
30495 this.fireEvent("resize", this, width, height);
30501 * Resizes the dialog to fit the specified content size.
30502 * @param {Number} width
30503 * @param {Number} height
30504 * @return {Roo.BasicDialog} this
30506 setContentSize : function(w, h){
30507 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30508 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30509 //if(!this.el.isBorderBox()){
30510 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30511 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30514 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30515 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30517 this.resizeTo(w, h);
30522 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30523 * executed in response to a particular key being pressed while the dialog is active.
30524 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30525 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30526 * @param {Function} fn The function to call
30527 * @param {Object} scope (optional) The scope of the function
30528 * @return {Roo.BasicDialog} this
30530 addKeyListener : function(key, fn, scope){
30531 var keyCode, shift, ctrl, alt;
30532 if(typeof key == "object" && !(key instanceof Array)){
30533 keyCode = key["key"];
30534 shift = key["shift"];
30535 ctrl = key["ctrl"];
30540 var handler = function(dlg, e){
30541 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30542 var k = e.getKey();
30543 if(keyCode instanceof Array){
30544 for(var i = 0, len = keyCode.length; i < len; i++){
30545 if(keyCode[i] == k){
30546 fn.call(scope || window, dlg, k, e);
30552 fn.call(scope || window, dlg, k, e);
30557 this.on("keydown", handler);
30562 * Returns the TabPanel component (creates it if it doesn't exist).
30563 * Note: If you wish to simply check for the existence of tabs without creating them,
30564 * check for a null 'tabs' property.
30565 * @return {Roo.TabPanel} The tabs component
30567 getTabs : function(){
30569 this.el.addClass("x-dlg-auto-tabs");
30570 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30571 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30577 * Adds a button to the footer section of the dialog.
30578 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30579 * object or a valid Roo.DomHelper element config
30580 * @param {Function} handler The function called when the button is clicked
30581 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30582 * @return {Roo.Button} The new button
30584 addButton : function(config, handler, scope){
30585 var dh = Roo.DomHelper;
30587 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30589 if(!this.btnContainer){
30590 var tb = this.footer.createChild({
30592 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30593 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30595 this.btnContainer = tb.firstChild.firstChild.firstChild;
30600 minWidth: this.minButtonWidth,
30603 if(typeof config == "string"){
30604 bconfig.text = config;
30607 bconfig.dhconfig = config;
30609 Roo.apply(bconfig, config);
30613 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30614 bconfig.position = Math.max(0, bconfig.position);
30615 fc = this.btnContainer.childNodes[bconfig.position];
30618 var btn = new Roo.Button(
30620 this.btnContainer.insertBefore(document.createElement("td"),fc)
30621 : this.btnContainer.appendChild(document.createElement("td")),
30622 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30625 this.syncBodyHeight();
30628 * Array of all the buttons that have been added to this dialog via addButton
30633 this.buttons.push(btn);
30638 * Sets the default button to be focused when the dialog is displayed.
30639 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30640 * @return {Roo.BasicDialog} this
30642 setDefaultButton : function(btn){
30643 this.defaultButton = btn;
30648 getHeaderFooterHeight : function(safe){
30651 height += this.header.getHeight();
30654 var fm = this.footer.getMargins();
30655 height += (this.footer.getHeight()+fm.top+fm.bottom);
30657 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30658 height += this.centerBg.getPadding("tb");
30663 syncBodyHeight : function()
30665 var bd = this.body, // the text
30666 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30668 var height = this.size.height - this.getHeaderFooterHeight(false);
30669 bd.setHeight(height-bd.getMargins("tb"));
30670 var hh = this.header.getHeight();
30671 var h = this.size.height-hh;
30674 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30675 bw.setHeight(h-cb.getPadding("tb"));
30677 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30678 bd.setWidth(bw.getWidth(true));
30680 this.tabs.syncHeight();
30682 this.tabs.el.repaint();
30688 * Restores the previous state of the dialog if Roo.state is configured.
30689 * @return {Roo.BasicDialog} this
30691 restoreState : function(){
30692 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30693 if(box && box.width){
30694 this.xy = [box.x, box.y];
30695 this.resizeTo(box.width, box.height);
30701 beforeShow : function(){
30703 if(this.fixedcenter){
30704 this.xy = this.el.getCenterXY(true);
30707 Roo.get(document.body).addClass("x-body-masked");
30708 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30711 this.constrainXY();
30715 animShow : function(){
30716 var b = Roo.get(this.animateTarget).getBox();
30717 this.proxy.setSize(b.width, b.height);
30718 this.proxy.setLocation(b.x, b.y);
30720 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30721 true, .35, this.showEl.createDelegate(this));
30725 * Shows the dialog.
30726 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30727 * @return {Roo.BasicDialog} this
30729 show : function(animateTarget){
30730 if (this.fireEvent("beforeshow", this) === false){
30733 if(this.syncHeightBeforeShow){
30734 this.syncBodyHeight();
30735 }else if(this.firstShow){
30736 this.firstShow = false;
30737 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30739 this.animateTarget = animateTarget || this.animateTarget;
30740 if(!this.el.isVisible()){
30742 if(this.animateTarget && Roo.get(this.animateTarget)){
30752 showEl : function(){
30754 this.el.setXY(this.xy);
30756 this.adjustAssets(true);
30759 // IE peekaboo bug - fix found by Dave Fenwick
30763 this.fireEvent("show", this);
30767 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30768 * dialog itself will receive focus.
30770 focus : function(){
30771 if(this.defaultButton){
30772 this.defaultButton.focus();
30774 this.focusEl.focus();
30779 constrainXY : function(){
30780 if(this.constraintoviewport !== false){
30781 if(!this.viewSize){
30782 if(this.container){
30783 var s = this.container.getSize();
30784 this.viewSize = [s.width, s.height];
30786 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30789 var s = Roo.get(this.container||document).getScroll();
30791 var x = this.xy[0], y = this.xy[1];
30792 var w = this.size.width, h = this.size.height;
30793 var vw = this.viewSize[0], vh = this.viewSize[1];
30794 // only move it if it needs it
30796 // first validate right/bottom
30797 if(x + w > vw+s.left){
30801 if(y + h > vh+s.top){
30805 // then make sure top/left isn't negative
30817 if(this.isVisible()){
30818 this.el.setLocation(x, y);
30819 this.adjustAssets();
30826 onDrag : function(){
30827 if(!this.proxyDrag){
30828 this.xy = this.el.getXY();
30829 this.adjustAssets();
30834 adjustAssets : function(doShow){
30835 var x = this.xy[0], y = this.xy[1];
30836 var w = this.size.width, h = this.size.height;
30837 if(doShow === true){
30839 this.shadow.show(this.el);
30845 if(this.shadow && this.shadow.isVisible()){
30846 this.shadow.show(this.el);
30848 if(this.shim && this.shim.isVisible()){
30849 this.shim.setBounds(x, y, w, h);
30854 adjustViewport : function(w, h){
30856 w = Roo.lib.Dom.getViewWidth();
30857 h = Roo.lib.Dom.getViewHeight();
30860 this.viewSize = [w, h];
30861 if(this.modal && this.mask.isVisible()){
30862 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30863 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30865 if(this.isVisible()){
30866 this.constrainXY();
30871 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30872 * shadow, proxy, mask, etc.) Also removes all event listeners.
30873 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30875 destroy : function(removeEl){
30876 if(this.isVisible()){
30877 this.animateTarget = null;
30880 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30882 this.tabs.destroy(removeEl);
30895 for(var i = 0, len = this.buttons.length; i < len; i++){
30896 this.buttons[i].destroy();
30899 this.el.removeAllListeners();
30900 if(removeEl === true){
30901 this.el.update("");
30904 Roo.DialogManager.unregister(this);
30908 startMove : function(){
30909 if(this.proxyDrag){
30912 if(this.constraintoviewport !== false){
30913 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30918 endMove : function(){
30919 if(!this.proxyDrag){
30920 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30922 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30925 this.refreshSize();
30926 this.adjustAssets();
30928 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30932 * Brings this dialog to the front of any other visible dialogs
30933 * @return {Roo.BasicDialog} this
30935 toFront : function(){
30936 Roo.DialogManager.bringToFront(this);
30941 * Sends this dialog to the back (under) of any other visible dialogs
30942 * @return {Roo.BasicDialog} this
30944 toBack : function(){
30945 Roo.DialogManager.sendToBack(this);
30950 * Centers this dialog in the viewport
30951 * @return {Roo.BasicDialog} this
30953 center : function(){
30954 var xy = this.el.getCenterXY(true);
30955 this.moveTo(xy[0], xy[1]);
30960 * Moves the dialog's top-left corner to the specified point
30961 * @param {Number} x
30962 * @param {Number} y
30963 * @return {Roo.BasicDialog} this
30965 moveTo : function(x, y){
30967 if(this.isVisible()){
30968 this.el.setXY(this.xy);
30969 this.adjustAssets();
30975 * Aligns the dialog to the specified element
30976 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30977 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30978 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30979 * @return {Roo.BasicDialog} this
30981 alignTo : function(element, position, offsets){
30982 this.xy = this.el.getAlignToXY(element, position, offsets);
30983 if(this.isVisible()){
30984 this.el.setXY(this.xy);
30985 this.adjustAssets();
30991 * Anchors an element to another element and realigns it when the window is resized.
30992 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30993 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30994 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30995 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30996 * is a number, it is used as the buffer delay (defaults to 50ms).
30997 * @return {Roo.BasicDialog} this
30999 anchorTo : function(el, alignment, offsets, monitorScroll){
31000 var action = function(){
31001 this.alignTo(el, alignment, offsets);
31003 Roo.EventManager.onWindowResize(action, this);
31004 var tm = typeof monitorScroll;
31005 if(tm != 'undefined'){
31006 Roo.EventManager.on(window, 'scroll', action, this,
31007 {buffer: tm == 'number' ? monitorScroll : 50});
31014 * Returns true if the dialog is visible
31015 * @return {Boolean}
31017 isVisible : function(){
31018 return this.el.isVisible();
31022 animHide : function(callback){
31023 var b = Roo.get(this.animateTarget).getBox();
31025 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
31027 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
31028 this.hideEl.createDelegate(this, [callback]));
31032 * Hides the dialog.
31033 * @param {Function} callback (optional) Function to call when the dialog is hidden
31034 * @return {Roo.BasicDialog} this
31036 hide : function(callback){
31037 if (this.fireEvent("beforehide", this) === false){
31041 this.shadow.hide();
31046 // sometimes animateTarget seems to get set.. causing problems...
31047 // this just double checks..
31048 if(this.animateTarget && Roo.get(this.animateTarget)) {
31049 this.animHide(callback);
31052 this.hideEl(callback);
31058 hideEl : function(callback){
31062 Roo.get(document.body).removeClass("x-body-masked");
31064 this.fireEvent("hide", this);
31065 if(typeof callback == "function"){
31071 hideAction : function(){
31072 this.setLeft("-10000px");
31073 this.setTop("-10000px");
31074 this.setStyle("visibility", "hidden");
31078 refreshSize : function(){
31079 this.size = this.el.getSize();
31080 this.xy = this.el.getXY();
31081 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31085 // z-index is managed by the DialogManager and may be overwritten at any time
31086 setZIndex : function(index){
31088 this.mask.setStyle("z-index", index);
31091 this.shim.setStyle("z-index", ++index);
31094 this.shadow.setZIndex(++index);
31096 this.el.setStyle("z-index", ++index);
31098 this.proxy.setStyle("z-index", ++index);
31101 this.resizer.proxy.setStyle("z-index", ++index);
31104 this.lastZIndex = index;
31108 * Returns the element for this dialog
31109 * @return {Roo.Element} The underlying dialog Element
31111 getEl : function(){
31117 * @class Roo.DialogManager
31118 * Provides global access to BasicDialogs that have been created and
31119 * support for z-indexing (layering) multiple open dialogs.
31121 Roo.DialogManager = function(){
31123 var accessList = [];
31127 var sortDialogs = function(d1, d2){
31128 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31132 var orderDialogs = function(){
31133 accessList.sort(sortDialogs);
31134 var seed = Roo.DialogManager.zseed;
31135 for(var i = 0, len = accessList.length; i < len; i++){
31136 var dlg = accessList[i];
31138 dlg.setZIndex(seed + (i*10));
31145 * The starting z-index for BasicDialogs (defaults to 9000)
31146 * @type Number The z-index value
31151 register : function(dlg){
31152 list[dlg.id] = dlg;
31153 accessList.push(dlg);
31157 unregister : function(dlg){
31158 delete list[dlg.id];
31161 if(!accessList.indexOf){
31162 for( i = 0, len = accessList.length; i < len; i++){
31163 if(accessList[i] == dlg){
31164 accessList.splice(i, 1);
31169 i = accessList.indexOf(dlg);
31171 accessList.splice(i, 1);
31177 * Gets a registered dialog by id
31178 * @param {String/Object} id The id of the dialog or a dialog
31179 * @return {Roo.BasicDialog} this
31181 get : function(id){
31182 return typeof id == "object" ? id : list[id];
31186 * Brings the specified dialog to the front
31187 * @param {String/Object} dlg The id of the dialog or a dialog
31188 * @return {Roo.BasicDialog} this
31190 bringToFront : function(dlg){
31191 dlg = this.get(dlg);
31194 dlg._lastAccess = new Date().getTime();
31201 * Sends the specified dialog to the back
31202 * @param {String/Object} dlg The id of the dialog or a dialog
31203 * @return {Roo.BasicDialog} this
31205 sendToBack : function(dlg){
31206 dlg = this.get(dlg);
31207 dlg._lastAccess = -(new Date().getTime());
31213 * Hides all dialogs
31215 hideAll : function(){
31216 for(var id in list){
31217 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31226 * @class Roo.LayoutDialog
31227 * @extends Roo.BasicDialog
31228 * Dialog which provides adjustments for working with a layout in a Dialog.
31229 * Add your necessary layout config options to the dialog's config.<br>
31230 * Example usage (including a nested layout):
31233 dialog = new Roo.LayoutDialog("download-dlg", {
31242 // layout config merges with the dialog config
31244 tabPosition: "top",
31245 alwaysShowTabs: true
31248 dialog.addKeyListener(27, dialog.hide, dialog);
31249 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31250 dialog.addButton("Build It!", this.getDownload, this);
31252 // we can even add nested layouts
31253 var innerLayout = new Roo.BorderLayout("dl-inner", {
31263 innerLayout.beginUpdate();
31264 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31265 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31266 innerLayout.endUpdate(true);
31268 var layout = dialog.getLayout();
31269 layout.beginUpdate();
31270 layout.add("center", new Roo.ContentPanel("standard-panel",
31271 {title: "Download the Source", fitToFrame:true}));
31272 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31273 {title: "Build your own roo.js"}));
31274 layout.getRegion("center").showPanel(sp);
31275 layout.endUpdate();
31279 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31280 * @param {Object} config configuration options
31282 Roo.LayoutDialog = function(el, cfg){
31285 if (typeof(cfg) == 'undefined') {
31286 config = Roo.apply({}, el);
31287 // not sure why we use documentElement here.. - it should always be body.
31288 // IE7 borks horribly if we use documentElement.
31289 // webkit also does not like documentElement - it creates a body element...
31290 el = Roo.get( document.body || document.documentElement ).createChild();
31291 //config.autoCreate = true;
31295 config.autoTabs = false;
31296 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31297 this.body.setStyle({overflow:"hidden", position:"relative"});
31298 this.layout = new Roo.BorderLayout(this.body.dom, config);
31299 this.layout.monitorWindowResize = false;
31300 this.el.addClass("x-dlg-auto-layout");
31301 // fix case when center region overwrites center function
31302 this.center = Roo.BasicDialog.prototype.center;
31303 this.on("show", this.layout.layout, this.layout, true);
31304 if (config.items) {
31305 var xitems = config.items;
31306 delete config.items;
31307 Roo.each(xitems, this.addxtype, this);
31312 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31314 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31317 endUpdate : function(){
31318 this.layout.endUpdate();
31322 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31325 beginUpdate : function(){
31326 this.layout.beginUpdate();
31330 * Get the BorderLayout for this dialog
31331 * @return {Roo.BorderLayout}
31333 getLayout : function(){
31334 return this.layout;
31337 showEl : function(){
31338 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31340 this.layout.layout();
31345 // Use the syncHeightBeforeShow config option to control this automatically
31346 syncBodyHeight : function(){
31347 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31348 if(this.layout){this.layout.layout();}
31352 * Add an xtype element (actually adds to the layout.)
31353 * @return {Object} xdata xtype object data.
31356 addxtype : function(c) {
31357 return this.layout.addxtype(c);
31361 * Ext JS Library 1.1.1
31362 * Copyright(c) 2006-2007, Ext JS, LLC.
31364 * Originally Released Under LGPL - original licence link has changed is not relivant.
31367 * <script type="text/javascript">
31371 * @class Roo.MessageBox
31372 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31376 Roo.Msg.alert('Status', 'Changes saved successfully.');
31378 // Prompt for user data:
31379 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31381 // process text value...
31385 // Show a dialog using config options:
31387 title:'Save Changes?',
31388 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31389 buttons: Roo.Msg.YESNOCANCEL,
31396 Roo.MessageBox = function(){
31397 var dlg, opt, mask, waitTimer;
31398 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31399 var buttons, activeTextEl, bwidth;
31402 var handleButton = function(button){
31404 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31408 var handleHide = function(){
31409 if(opt && opt.cls){
31410 dlg.el.removeClass(opt.cls);
31413 Roo.TaskMgr.stop(waitTimer);
31419 var updateButtons = function(b){
31422 buttons["ok"].hide();
31423 buttons["cancel"].hide();
31424 buttons["yes"].hide();
31425 buttons["no"].hide();
31426 dlg.footer.dom.style.display = 'none';
31429 dlg.footer.dom.style.display = '';
31430 for(var k in buttons){
31431 if(typeof buttons[k] != "function"){
31434 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31435 width += buttons[k].el.getWidth()+15;
31445 var handleEsc = function(d, k, e){
31446 if(opt && opt.closable !== false){
31456 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31457 * @return {Roo.BasicDialog} The BasicDialog element
31459 getDialog : function(){
31461 dlg = new Roo.BasicDialog("x-msg-box", {
31466 constraintoviewport:false,
31468 collapsible : false,
31471 width:400, height:100,
31472 buttonAlign:"center",
31473 closeClick : function(){
31474 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31475 handleButton("no");
31477 handleButton("cancel");
31481 dlg.on("hide", handleHide);
31483 dlg.addKeyListener(27, handleEsc);
31485 var bt = this.buttonText;
31486 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31487 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31488 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31489 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31490 bodyEl = dlg.body.createChild({
31492 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>'
31494 msgEl = bodyEl.dom.firstChild;
31495 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31496 textboxEl.enableDisplayMode();
31497 textboxEl.addKeyListener([10,13], function(){
31498 if(dlg.isVisible() && opt && opt.buttons){
31499 if(opt.buttons.ok){
31500 handleButton("ok");
31501 }else if(opt.buttons.yes){
31502 handleButton("yes");
31506 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31507 textareaEl.enableDisplayMode();
31508 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31509 progressEl.enableDisplayMode();
31510 var pf = progressEl.dom.firstChild;
31512 pp = Roo.get(pf.firstChild);
31513 pp.setHeight(pf.offsetHeight);
31521 * Updates the message box body text
31522 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31523 * the XHTML-compliant non-breaking space character '&#160;')
31524 * @return {Roo.MessageBox} This message box
31526 updateText : function(text){
31527 if(!dlg.isVisible() && !opt.width){
31528 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31530 msgEl.innerHTML = text || ' ';
31532 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31533 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31535 Math.min(opt.width || cw , this.maxWidth),
31536 Math.max(opt.minWidth || this.minWidth, bwidth)
31539 activeTextEl.setWidth(w);
31541 if(dlg.isVisible()){
31542 dlg.fixedcenter = false;
31544 // to big, make it scroll. = But as usual stupid IE does not support
31547 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31548 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31549 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31551 bodyEl.dom.style.height = '';
31552 bodyEl.dom.style.overflowY = '';
31555 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31557 bodyEl.dom.style.overflowX = '';
31560 dlg.setContentSize(w, bodyEl.getHeight());
31561 if(dlg.isVisible()){
31562 dlg.fixedcenter = true;
31568 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31569 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31570 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31571 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31572 * @return {Roo.MessageBox} This message box
31574 updateProgress : function(value, text){
31576 this.updateText(text);
31578 if (pp) { // weird bug on my firefox - for some reason this is not defined
31579 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31585 * Returns true if the message box is currently displayed
31586 * @return {Boolean} True if the message box is visible, else false
31588 isVisible : function(){
31589 return dlg && dlg.isVisible();
31593 * Hides the message box if it is displayed
31596 if(this.isVisible()){
31602 * Displays a new message box, or reinitializes an existing message box, based on the config options
31603 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31604 * The following config object properties are supported:
31606 Property Type Description
31607 ---------- --------------- ------------------------------------------------------------------------------------
31608 animEl String/Element An id or Element from which the message box should animate as it opens and
31609 closes (defaults to undefined)
31610 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31611 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31612 closable Boolean False to hide the top-right close button (defaults to true). Note that
31613 progress and wait dialogs will ignore this property and always hide the
31614 close button as they can only be closed programmatically.
31615 cls String A custom CSS class to apply to the message box element
31616 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31617 displayed (defaults to 75)
31618 fn Function A callback function to execute after closing the dialog. The arguments to the
31619 function will be btn (the name of the button that was clicked, if applicable,
31620 e.g. "ok"), and text (the value of the active text field, if applicable).
31621 Progress and wait dialogs will ignore this option since they do not respond to
31622 user actions and can only be closed programmatically, so any required function
31623 should be called by the same code after it closes the dialog.
31624 icon String A CSS class that provides a background image to be used as an icon for
31625 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31626 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31627 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31628 modal Boolean False to allow user interaction with the page while the message box is
31629 displayed (defaults to true)
31630 msg String A string that will replace the existing message box body text (defaults
31631 to the XHTML-compliant non-breaking space character ' ')
31632 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31633 progress Boolean True to display a progress bar (defaults to false)
31634 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31635 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31636 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31637 title String The title text
31638 value String The string value to set into the active textbox element if displayed
31639 wait Boolean True to display a progress bar (defaults to false)
31640 width Number The width of the dialog in pixels
31647 msg: 'Please enter your address:',
31649 buttons: Roo.MessageBox.OKCANCEL,
31652 animEl: 'addAddressBtn'
31655 * @param {Object} config Configuration options
31656 * @return {Roo.MessageBox} This message box
31658 show : function(options)
31661 // this causes nightmares if you show one dialog after another
31662 // especially on callbacks..
31664 if(this.isVisible()){
31667 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31668 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31669 Roo.log("New Dialog Message:" + options.msg )
31670 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31671 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31674 var d = this.getDialog();
31676 d.setTitle(opt.title || " ");
31677 d.close.setDisplayed(opt.closable !== false);
31678 activeTextEl = textboxEl;
31679 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31684 textareaEl.setHeight(typeof opt.multiline == "number" ?
31685 opt.multiline : this.defaultTextHeight);
31686 activeTextEl = textareaEl;
31695 progressEl.setDisplayed(opt.progress === true);
31696 this.updateProgress(0);
31697 activeTextEl.dom.value = opt.value || "";
31699 dlg.setDefaultButton(activeTextEl);
31701 var bs = opt.buttons;
31704 db = buttons["ok"];
31705 }else if(bs && bs.yes){
31706 db = buttons["yes"];
31708 dlg.setDefaultButton(db);
31710 bwidth = updateButtons(opt.buttons);
31711 this.updateText(opt.msg);
31713 d.el.addClass(opt.cls);
31715 d.proxyDrag = opt.proxyDrag === true;
31716 d.modal = opt.modal !== false;
31717 d.mask = opt.modal !== false ? mask : false;
31718 if(!d.isVisible()){
31719 // force it to the end of the z-index stack so it gets a cursor in FF
31720 document.body.appendChild(dlg.el.dom);
31721 d.animateTarget = null;
31722 d.show(options.animEl);
31728 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31729 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31730 * and closing the message box when the process is complete.
31731 * @param {String} title The title bar text
31732 * @param {String} msg The message box body text
31733 * @return {Roo.MessageBox} This message box
31735 progress : function(title, msg){
31742 minWidth: this.minProgressWidth,
31749 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31750 * If a callback function is passed it will be called after the user clicks the button, and the
31751 * id of the button that was clicked will be passed as the only parameter to the callback
31752 * (could also be the top-right close button).
31753 * @param {String} title The title bar text
31754 * @param {String} msg The message box body text
31755 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31756 * @param {Object} scope (optional) The scope of the callback function
31757 * @return {Roo.MessageBox} This message box
31759 alert : function(title, msg, fn, scope){
31772 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31773 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31774 * You are responsible for closing the message box when the process is complete.
31775 * @param {String} msg The message box body text
31776 * @param {String} title (optional) The title bar text
31777 * @return {Roo.MessageBox} This message box
31779 wait : function(msg, title){
31790 waitTimer = Roo.TaskMgr.start({
31792 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31800 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31801 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31802 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31803 * @param {String} title The title bar text
31804 * @param {String} msg The message box body text
31805 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31806 * @param {Object} scope (optional) The scope of the callback function
31807 * @return {Roo.MessageBox} This message box
31809 confirm : function(title, msg, fn, scope){
31813 buttons: this.YESNO,
31822 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31823 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31824 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31825 * (could also be the top-right close button) and the text that was entered will be passed as the two
31826 * parameters to the callback.
31827 * @param {String} title The title bar text
31828 * @param {String} msg The message box body text
31829 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31830 * @param {Object} scope (optional) The scope of the callback function
31831 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31832 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31833 * @return {Roo.MessageBox} This message box
31835 prompt : function(title, msg, fn, scope, multiline){
31839 buttons: this.OKCANCEL,
31844 multiline: multiline,
31851 * Button config that displays a single OK button
31856 * Button config that displays Yes and No buttons
31859 YESNO : {yes:true, no:true},
31861 * Button config that displays OK and Cancel buttons
31864 OKCANCEL : {ok:true, cancel:true},
31866 * Button config that displays Yes, No and Cancel buttons
31869 YESNOCANCEL : {yes:true, no:true, cancel:true},
31872 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31875 defaultTextHeight : 75,
31877 * The maximum width in pixels of the message box (defaults to 600)
31882 * The minimum width in pixels of the message box (defaults to 100)
31887 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31888 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31891 minProgressWidth : 250,
31893 * An object containing the default button text strings that can be overriden for localized language support.
31894 * Supported properties are: ok, cancel, yes and no.
31895 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31908 * Shorthand for {@link Roo.MessageBox}
31910 Roo.Msg = Roo.MessageBox;/*
31912 * Ext JS Library 1.1.1
31913 * Copyright(c) 2006-2007, Ext JS, LLC.
31915 * Originally Released Under LGPL - original licence link has changed is not relivant.
31918 * <script type="text/javascript">
31921 * @class Roo.QuickTips
31922 * Provides attractive and customizable tooltips for any element.
31925 Roo.QuickTips = function(){
31926 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31927 var ce, bd, xy, dd;
31928 var visible = false, disabled = true, inited = false;
31929 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31931 var onOver = function(e){
31935 var t = e.getTarget();
31936 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31939 if(ce && t == ce.el){
31940 clearTimeout(hideProc);
31943 if(t && tagEls[t.id]){
31944 tagEls[t.id].el = t;
31945 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31948 var ttp, et = Roo.fly(t);
31949 var ns = cfg.namespace;
31950 if(tm.interceptTitles && t.title){
31953 t.removeAttribute("title");
31954 e.preventDefault();
31956 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31959 showProc = show.defer(tm.showDelay, tm, [{
31962 width: et.getAttributeNS(ns, cfg.width),
31963 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31964 title: et.getAttributeNS(ns, cfg.title),
31965 cls: et.getAttributeNS(ns, cfg.cls)
31970 var onOut = function(e){
31971 clearTimeout(showProc);
31972 var t = e.getTarget();
31973 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31974 hideProc = setTimeout(hide, tm.hideDelay);
31978 var onMove = function(e){
31984 if(tm.trackMouse && ce){
31989 var onDown = function(e){
31990 clearTimeout(showProc);
31991 clearTimeout(hideProc);
31993 if(tm.hideOnClick){
31996 tm.enable.defer(100, tm);
32001 var getPad = function(){
32002 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
32005 var show = function(o){
32009 clearTimeout(dismissProc);
32011 if(removeCls){ // in case manually hidden
32012 el.removeClass(removeCls);
32016 el.addClass(ce.cls);
32017 removeCls = ce.cls;
32020 tipTitle.update(ce.title);
32023 tipTitle.update('');
32026 el.dom.style.width = tm.maxWidth+'px';
32027 //tipBody.dom.style.width = '';
32028 tipBodyText.update(o.text);
32029 var p = getPad(), w = ce.width;
32031 var td = tipBodyText.dom;
32032 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
32033 if(aw > tm.maxWidth){
32035 }else if(aw < tm.minWidth){
32041 //tipBody.setWidth(w);
32042 el.setWidth(parseInt(w, 10) + p);
32043 if(ce.autoHide === false){
32044 close.setDisplayed(true);
32049 close.setDisplayed(false);
32055 el.avoidY = xy[1]-18;
32060 el.setStyle("visibility", "visible");
32061 el.fadeIn({callback: afterShow});
32067 var afterShow = function(){
32071 if(tm.autoDismiss && ce.autoHide !== false){
32072 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32077 var hide = function(noanim){
32078 clearTimeout(dismissProc);
32079 clearTimeout(hideProc);
32081 if(el.isVisible()){
32083 if(noanim !== true && tm.animate){
32084 el.fadeOut({callback: afterHide});
32091 var afterHide = function(){
32094 el.removeClass(removeCls);
32101 * @cfg {Number} minWidth
32102 * The minimum width of the quick tip (defaults to 40)
32106 * @cfg {Number} maxWidth
32107 * The maximum width of the quick tip (defaults to 300)
32111 * @cfg {Boolean} interceptTitles
32112 * True to automatically use the element's DOM title value if available (defaults to false)
32114 interceptTitles : false,
32116 * @cfg {Boolean} trackMouse
32117 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32119 trackMouse : false,
32121 * @cfg {Boolean} hideOnClick
32122 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32124 hideOnClick : true,
32126 * @cfg {Number} showDelay
32127 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32131 * @cfg {Number} hideDelay
32132 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32136 * @cfg {Boolean} autoHide
32137 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32138 * Used in conjunction with hideDelay.
32143 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32144 * (defaults to true). Used in conjunction with autoDismissDelay.
32146 autoDismiss : true,
32149 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32151 autoDismissDelay : 5000,
32153 * @cfg {Boolean} animate
32154 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32159 * @cfg {String} title
32160 * Title text to display (defaults to ''). This can be any valid HTML markup.
32164 * @cfg {String} text
32165 * Body text to display (defaults to ''). This can be any valid HTML markup.
32169 * @cfg {String} cls
32170 * A CSS class to apply to the base quick tip element (defaults to '').
32174 * @cfg {Number} width
32175 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32176 * minWidth or maxWidth.
32181 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32182 * or display QuickTips in a page.
32185 tm = Roo.QuickTips;
32186 cfg = tm.tagConfig;
32188 if(!Roo.isReady){ // allow calling of init() before onReady
32189 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32192 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32193 el.fxDefaults = {stopFx: true};
32194 // maximum custom styling
32195 //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>');
32196 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>');
32197 tipTitle = el.child('h3');
32198 tipTitle.enableDisplayMode("block");
32199 tipBody = el.child('div.x-tip-bd');
32200 tipBodyText = el.child('div.x-tip-bd-inner');
32201 //bdLeft = el.child('div.x-tip-bd-left');
32202 //bdRight = el.child('div.x-tip-bd-right');
32203 close = el.child('div.x-tip-close');
32204 close.enableDisplayMode("block");
32205 close.on("click", hide);
32206 var d = Roo.get(document);
32207 d.on("mousedown", onDown);
32208 d.on("mouseover", onOver);
32209 d.on("mouseout", onOut);
32210 d.on("mousemove", onMove);
32211 esc = d.addKeyListener(27, hide);
32214 dd = el.initDD("default", null, {
32215 onDrag : function(){
32219 dd.setHandleElId(tipTitle.id);
32228 * Configures a new quick tip instance and assigns it to a target element. The following config options
32231 Property Type Description
32232 ---------- --------------------- ------------------------------------------------------------------------
32233 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32235 * @param {Object} config The config object
32237 register : function(config){
32238 var cs = config instanceof Array ? config : arguments;
32239 for(var i = 0, len = cs.length; i < len; i++) {
32241 var target = c.target;
32243 if(target instanceof Array){
32244 for(var j = 0, jlen = target.length; j < jlen; j++){
32245 tagEls[target[j]] = c;
32248 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32255 * Removes this quick tip from its element and destroys it.
32256 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32258 unregister : function(el){
32259 delete tagEls[Roo.id(el)];
32263 * Enable this quick tip.
32265 enable : function(){
32266 if(inited && disabled){
32268 if(locks.length < 1){
32275 * Disable this quick tip.
32277 disable : function(){
32279 clearTimeout(showProc);
32280 clearTimeout(hideProc);
32281 clearTimeout(dismissProc);
32289 * Returns true if the quick tip is enabled, else false.
32291 isEnabled : function(){
32298 attribute : "qtip",
32308 // backwards compat
32309 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32311 * Ext JS Library 1.1.1
32312 * Copyright(c) 2006-2007, Ext JS, LLC.
32314 * Originally Released Under LGPL - original licence link has changed is not relivant.
32317 * <script type="text/javascript">
32322 * @class Roo.tree.TreePanel
32323 * @extends Roo.data.Tree
32325 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32326 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32327 * @cfg {Boolean} enableDD true to enable drag and drop
32328 * @cfg {Boolean} enableDrag true to enable just drag
32329 * @cfg {Boolean} enableDrop true to enable just drop
32330 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32331 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32332 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32333 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32334 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32335 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32336 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32337 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32338 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32339 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32340 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32341 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32342 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32343 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32344 * @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>
32345 * @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>
32348 * @param {String/HTMLElement/Element} el The container element
32349 * @param {Object} config
32351 Roo.tree.TreePanel = function(el, config){
32353 var loader = false;
32355 root = config.root;
32356 delete config.root;
32358 if (config.loader) {
32359 loader = config.loader;
32360 delete config.loader;
32363 Roo.apply(this, config);
32364 Roo.tree.TreePanel.superclass.constructor.call(this);
32365 this.el = Roo.get(el);
32366 this.el.addClass('x-tree');
32367 //console.log(root);
32369 this.setRootNode( Roo.factory(root, Roo.tree));
32372 this.loader = Roo.factory(loader, Roo.tree);
32375 * Read-only. The id of the container element becomes this TreePanel's id.
32377 this.id = this.el.id;
32380 * @event beforeload
32381 * Fires before a node is loaded, return false to cancel
32382 * @param {Node} node The node being loaded
32384 "beforeload" : true,
32387 * Fires when a node is loaded
32388 * @param {Node} node The node that was loaded
32392 * @event textchange
32393 * Fires when the text for a node is changed
32394 * @param {Node} node The node
32395 * @param {String} text The new text
32396 * @param {String} oldText The old text
32398 "textchange" : true,
32400 * @event beforeexpand
32401 * Fires before a node is expanded, return false to cancel.
32402 * @param {Node} node The node
32403 * @param {Boolean} deep
32404 * @param {Boolean} anim
32406 "beforeexpand" : true,
32408 * @event beforecollapse
32409 * Fires before a node is collapsed, return false to cancel.
32410 * @param {Node} node The node
32411 * @param {Boolean} deep
32412 * @param {Boolean} anim
32414 "beforecollapse" : true,
32417 * Fires when a node is expanded
32418 * @param {Node} node The node
32422 * @event disabledchange
32423 * Fires when the disabled status of a node changes
32424 * @param {Node} node The node
32425 * @param {Boolean} disabled
32427 "disabledchange" : true,
32430 * Fires when a node is collapsed
32431 * @param {Node} node The node
32435 * @event beforeclick
32436 * Fires before click processing on a node. Return false to cancel the default action.
32437 * @param {Node} node The node
32438 * @param {Roo.EventObject} e The event object
32440 "beforeclick":true,
32442 * @event checkchange
32443 * Fires when a node with a checkbox's checked property changes
32444 * @param {Node} this This node
32445 * @param {Boolean} checked
32447 "checkchange":true,
32450 * Fires when a node is clicked
32451 * @param {Node} node The node
32452 * @param {Roo.EventObject} e The event object
32457 * Fires when a node is double clicked
32458 * @param {Node} node The node
32459 * @param {Roo.EventObject} e The event object
32463 * @event contextmenu
32464 * Fires when a node is right clicked
32465 * @param {Node} node The node
32466 * @param {Roo.EventObject} e The event object
32468 "contextmenu":true,
32470 * @event beforechildrenrendered
32471 * Fires right before the child nodes for a node are rendered
32472 * @param {Node} node The node
32474 "beforechildrenrendered":true,
32477 * Fires when a node starts being dragged
32478 * @param {Roo.tree.TreePanel} this
32479 * @param {Roo.tree.TreeNode} node
32480 * @param {event} e The raw browser event
32482 "startdrag" : true,
32485 * Fires when a drag operation is complete
32486 * @param {Roo.tree.TreePanel} this
32487 * @param {Roo.tree.TreeNode} node
32488 * @param {event} e The raw browser event
32493 * Fires when a dragged node is dropped on a valid DD target
32494 * @param {Roo.tree.TreePanel} this
32495 * @param {Roo.tree.TreeNode} node
32496 * @param {DD} dd The dd it was dropped on
32497 * @param {event} e The raw browser event
32501 * @event beforenodedrop
32502 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32503 * passed to handlers has the following properties:<br />
32504 * <ul style="padding:5px;padding-left:16px;">
32505 * <li>tree - The TreePanel</li>
32506 * <li>target - The node being targeted for the drop</li>
32507 * <li>data - The drag data from the drag source</li>
32508 * <li>point - The point of the drop - append, above or below</li>
32509 * <li>source - The drag source</li>
32510 * <li>rawEvent - Raw mouse event</li>
32511 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32512 * to be inserted by setting them on this object.</li>
32513 * <li>cancel - Set this to true to cancel the drop.</li>
32515 * @param {Object} dropEvent
32517 "beforenodedrop" : true,
32520 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32521 * passed to handlers has the following properties:<br />
32522 * <ul style="padding:5px;padding-left:16px;">
32523 * <li>tree - The TreePanel</li>
32524 * <li>target - The node being targeted for the drop</li>
32525 * <li>data - The drag data from the drag source</li>
32526 * <li>point - The point of the drop - append, above or below</li>
32527 * <li>source - The drag source</li>
32528 * <li>rawEvent - Raw mouse event</li>
32529 * <li>dropNode - Dropped node(s).</li>
32531 * @param {Object} dropEvent
32535 * @event nodedragover
32536 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32537 * passed to handlers has the following properties:<br />
32538 * <ul style="padding:5px;padding-left:16px;">
32539 * <li>tree - The TreePanel</li>
32540 * <li>target - The node being targeted for the drop</li>
32541 * <li>data - The drag data from the drag source</li>
32542 * <li>point - The point of the drop - append, above or below</li>
32543 * <li>source - The drag source</li>
32544 * <li>rawEvent - Raw mouse event</li>
32545 * <li>dropNode - Drop node(s) provided by the source.</li>
32546 * <li>cancel - Set this to true to signal drop not allowed.</li>
32548 * @param {Object} dragOverEvent
32550 "nodedragover" : true
32553 if(this.singleExpand){
32554 this.on("beforeexpand", this.restrictExpand, this);
32557 this.editor.tree = this;
32558 this.editor = Roo.factory(this.editor, Roo.tree);
32561 if (this.selModel) {
32562 this.selModel = Roo.factory(this.selModel, Roo.tree);
32566 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32567 rootVisible : true,
32568 animate: Roo.enableFx,
32571 hlDrop : Roo.enableFx,
32575 rendererTip: false,
32577 restrictExpand : function(node){
32578 var p = node.parentNode;
32580 if(p.expandedChild && p.expandedChild.parentNode == p){
32581 p.expandedChild.collapse();
32583 p.expandedChild = node;
32587 // private override
32588 setRootNode : function(node){
32589 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32590 if(!this.rootVisible){
32591 node.ui = new Roo.tree.RootTreeNodeUI(node);
32597 * Returns the container element for this TreePanel
32599 getEl : function(){
32604 * Returns the default TreeLoader for this TreePanel
32606 getLoader : function(){
32607 return this.loader;
32613 expandAll : function(){
32614 this.root.expand(true);
32618 * Collapse all nodes
32620 collapseAll : function(){
32621 this.root.collapse(true);
32625 * Returns the selection model used by this TreePanel
32627 getSelectionModel : function(){
32628 if(!this.selModel){
32629 this.selModel = new Roo.tree.DefaultSelectionModel();
32631 return this.selModel;
32635 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32636 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32637 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32640 getChecked : function(a, startNode){
32641 startNode = startNode || this.root;
32643 var f = function(){
32644 if(this.attributes.checked){
32645 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32648 startNode.cascade(f);
32653 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32654 * @param {String} path
32655 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32656 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32657 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32659 expandPath : function(path, attr, callback){
32660 attr = attr || "id";
32661 var keys = path.split(this.pathSeparator);
32662 var curNode = this.root;
32663 if(curNode.attributes[attr] != keys[1]){ // invalid root
32665 callback(false, null);
32670 var f = function(){
32671 if(++index == keys.length){
32673 callback(true, curNode);
32677 var c = curNode.findChild(attr, keys[index]);
32680 callback(false, curNode);
32685 c.expand(false, false, f);
32687 curNode.expand(false, false, f);
32691 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32692 * @param {String} path
32693 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32694 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32695 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32697 selectPath : function(path, attr, callback){
32698 attr = attr || "id";
32699 var keys = path.split(this.pathSeparator);
32700 var v = keys.pop();
32701 if(keys.length > 0){
32702 var f = function(success, node){
32703 if(success && node){
32704 var n = node.findChild(attr, v);
32710 }else if(callback){
32711 callback(false, n);
32715 callback(false, n);
32719 this.expandPath(keys.join(this.pathSeparator), attr, f);
32721 this.root.select();
32723 callback(true, this.root);
32728 getTreeEl : function(){
32733 * Trigger rendering of this TreePanel
32735 render : function(){
32736 if (this.innerCt) {
32737 return this; // stop it rendering more than once!!
32740 this.innerCt = this.el.createChild({tag:"ul",
32741 cls:"x-tree-root-ct " +
32742 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32744 if(this.containerScroll){
32745 Roo.dd.ScrollManager.register(this.el);
32747 if((this.enableDD || this.enableDrop) && !this.dropZone){
32749 * The dropZone used by this tree if drop is enabled
32750 * @type Roo.tree.TreeDropZone
32752 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32753 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32756 if((this.enableDD || this.enableDrag) && !this.dragZone){
32758 * The dragZone used by this tree if drag is enabled
32759 * @type Roo.tree.TreeDragZone
32761 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32762 ddGroup: this.ddGroup || "TreeDD",
32763 scroll: this.ddScroll
32766 this.getSelectionModel().init(this);
32768 Roo.log("ROOT not set in tree");
32771 this.root.render();
32772 if(!this.rootVisible){
32773 this.root.renderChildren();
32779 * Ext JS Library 1.1.1
32780 * Copyright(c) 2006-2007, Ext JS, LLC.
32782 * Originally Released Under LGPL - original licence link has changed is not relivant.
32785 * <script type="text/javascript">
32790 * @class Roo.tree.DefaultSelectionModel
32791 * @extends Roo.util.Observable
32792 * The default single selection for a TreePanel.
32793 * @param {Object} cfg Configuration
32795 Roo.tree.DefaultSelectionModel = function(cfg){
32796 this.selNode = null;
32802 * @event selectionchange
32803 * Fires when the selected node changes
32804 * @param {DefaultSelectionModel} this
32805 * @param {TreeNode} node the new selection
32807 "selectionchange" : true,
32810 * @event beforeselect
32811 * Fires before the selected node changes, return false to cancel the change
32812 * @param {DefaultSelectionModel} this
32813 * @param {TreeNode} node the new selection
32814 * @param {TreeNode} node the old selection
32816 "beforeselect" : true
32819 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32822 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32823 init : function(tree){
32825 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32826 tree.on("click", this.onNodeClick, this);
32829 onNodeClick : function(node, e){
32830 if (e.ctrlKey && this.selNode == node) {
32831 this.unselect(node);
32839 * @param {TreeNode} node The node to select
32840 * @return {TreeNode} The selected node
32842 select : function(node){
32843 var last = this.selNode;
32844 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32846 last.ui.onSelectedChange(false);
32848 this.selNode = node;
32849 node.ui.onSelectedChange(true);
32850 this.fireEvent("selectionchange", this, node, last);
32857 * @param {TreeNode} node The node to unselect
32859 unselect : function(node){
32860 if(this.selNode == node){
32861 this.clearSelections();
32866 * Clear all selections
32868 clearSelections : function(){
32869 var n = this.selNode;
32871 n.ui.onSelectedChange(false);
32872 this.selNode = null;
32873 this.fireEvent("selectionchange", this, null);
32879 * Get the selected node
32880 * @return {TreeNode} The selected node
32882 getSelectedNode : function(){
32883 return this.selNode;
32887 * Returns true if the node is selected
32888 * @param {TreeNode} node The node to check
32889 * @return {Boolean}
32891 isSelected : function(node){
32892 return this.selNode == node;
32896 * Selects the node above the selected node in the tree, intelligently walking the nodes
32897 * @return TreeNode The new selection
32899 selectPrevious : function(){
32900 var s = this.selNode || this.lastSelNode;
32904 var ps = s.previousSibling;
32906 if(!ps.isExpanded() || ps.childNodes.length < 1){
32907 return this.select(ps);
32909 var lc = ps.lastChild;
32910 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32913 return this.select(lc);
32915 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32916 return this.select(s.parentNode);
32922 * Selects the node above the selected node in the tree, intelligently walking the nodes
32923 * @return TreeNode The new selection
32925 selectNext : function(){
32926 var s = this.selNode || this.lastSelNode;
32930 if(s.firstChild && s.isExpanded()){
32931 return this.select(s.firstChild);
32932 }else if(s.nextSibling){
32933 return this.select(s.nextSibling);
32934 }else if(s.parentNode){
32936 s.parentNode.bubble(function(){
32937 if(this.nextSibling){
32938 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32947 onKeyDown : function(e){
32948 var s = this.selNode || this.lastSelNode;
32949 // undesirable, but required
32954 var k = e.getKey();
32962 this.selectPrevious();
32965 e.preventDefault();
32966 if(s.hasChildNodes()){
32967 if(!s.isExpanded()){
32969 }else if(s.firstChild){
32970 this.select(s.firstChild, e);
32975 e.preventDefault();
32976 if(s.hasChildNodes() && s.isExpanded()){
32978 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32979 this.select(s.parentNode, e);
32987 * @class Roo.tree.MultiSelectionModel
32988 * @extends Roo.util.Observable
32989 * Multi selection for a TreePanel.
32990 * @param {Object} cfg Configuration
32992 Roo.tree.MultiSelectionModel = function(){
32993 this.selNodes = [];
32997 * @event selectionchange
32998 * Fires when the selected nodes change
32999 * @param {MultiSelectionModel} this
33000 * @param {Array} nodes Array of the selected nodes
33002 "selectionchange" : true
33004 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
33008 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
33009 init : function(tree){
33011 tree.getTreeEl().on("keydown", this.onKeyDown, this);
33012 tree.on("click", this.onNodeClick, this);
33015 onNodeClick : function(node, e){
33016 this.select(node, e, e.ctrlKey);
33021 * @param {TreeNode} node The node to select
33022 * @param {EventObject} e (optional) An event associated with the selection
33023 * @param {Boolean} keepExisting True to retain existing selections
33024 * @return {TreeNode} The selected node
33026 select : function(node, e, keepExisting){
33027 if(keepExisting !== true){
33028 this.clearSelections(true);
33030 if(this.isSelected(node)){
33031 this.lastSelNode = node;
33034 this.selNodes.push(node);
33035 this.selMap[node.id] = node;
33036 this.lastSelNode = node;
33037 node.ui.onSelectedChange(true);
33038 this.fireEvent("selectionchange", this, this.selNodes);
33044 * @param {TreeNode} node The node to unselect
33046 unselect : function(node){
33047 if(this.selMap[node.id]){
33048 node.ui.onSelectedChange(false);
33049 var sn = this.selNodes;
33052 index = sn.indexOf(node);
33054 for(var i = 0, len = sn.length; i < len; i++){
33062 this.selNodes.splice(index, 1);
33064 delete this.selMap[node.id];
33065 this.fireEvent("selectionchange", this, this.selNodes);
33070 * Clear all selections
33072 clearSelections : function(suppressEvent){
33073 var sn = this.selNodes;
33075 for(var i = 0, len = sn.length; i < len; i++){
33076 sn[i].ui.onSelectedChange(false);
33078 this.selNodes = [];
33080 if(suppressEvent !== true){
33081 this.fireEvent("selectionchange", this, this.selNodes);
33087 * Returns true if the node is selected
33088 * @param {TreeNode} node The node to check
33089 * @return {Boolean}
33091 isSelected : function(node){
33092 return this.selMap[node.id] ? true : false;
33096 * Returns an array of the selected nodes
33099 getSelectedNodes : function(){
33100 return this.selNodes;
33103 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33105 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33107 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33110 * Ext JS Library 1.1.1
33111 * Copyright(c) 2006-2007, Ext JS, LLC.
33113 * Originally Released Under LGPL - original licence link has changed is not relivant.
33116 * <script type="text/javascript">
33120 * @class Roo.tree.TreeNode
33121 * @extends Roo.data.Node
33122 * @cfg {String} text The text for this node
33123 * @cfg {Boolean} expanded true to start the node expanded
33124 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33125 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33126 * @cfg {Boolean} disabled true to start the node disabled
33127 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33128 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33129 * @cfg {String} cls A css class to be added to the node
33130 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33131 * @cfg {String} href URL of the link used for the node (defaults to #)
33132 * @cfg {String} hrefTarget target frame for the link
33133 * @cfg {String} qtip An Ext QuickTip for the node
33134 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33135 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33136 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33137 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33138 * (defaults to undefined with no checkbox rendered)
33140 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33142 Roo.tree.TreeNode = function(attributes){
33143 attributes = attributes || {};
33144 if(typeof attributes == "string"){
33145 attributes = {text: attributes};
33147 this.childrenRendered = false;
33148 this.rendered = false;
33149 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33150 this.expanded = attributes.expanded === true;
33151 this.isTarget = attributes.isTarget !== false;
33152 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33153 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33156 * Read-only. The text for this node. To change it use setText().
33159 this.text = attributes.text;
33161 * True if this node is disabled.
33164 this.disabled = attributes.disabled === true;
33168 * @event textchange
33169 * Fires when the text for this node is changed
33170 * @param {Node} this This node
33171 * @param {String} text The new text
33172 * @param {String} oldText The old text
33174 "textchange" : true,
33176 * @event beforeexpand
33177 * Fires before this node is expanded, return false to cancel.
33178 * @param {Node} this This node
33179 * @param {Boolean} deep
33180 * @param {Boolean} anim
33182 "beforeexpand" : true,
33184 * @event beforecollapse
33185 * Fires before this node is collapsed, return false to cancel.
33186 * @param {Node} this This node
33187 * @param {Boolean} deep
33188 * @param {Boolean} anim
33190 "beforecollapse" : true,
33193 * Fires when this node is expanded
33194 * @param {Node} this This node
33198 * @event disabledchange
33199 * Fires when the disabled status of this node changes
33200 * @param {Node} this This node
33201 * @param {Boolean} disabled
33203 "disabledchange" : true,
33206 * Fires when this node is collapsed
33207 * @param {Node} this This node
33211 * @event beforeclick
33212 * Fires before click processing. Return false to cancel the default action.
33213 * @param {Node} this This node
33214 * @param {Roo.EventObject} e The event object
33216 "beforeclick":true,
33218 * @event checkchange
33219 * Fires when a node with a checkbox's checked property changes
33220 * @param {Node} this This node
33221 * @param {Boolean} checked
33223 "checkchange":true,
33226 * Fires when this node is clicked
33227 * @param {Node} this This node
33228 * @param {Roo.EventObject} e The event object
33233 * Fires when this node is double clicked
33234 * @param {Node} this This node
33235 * @param {Roo.EventObject} e The event object
33239 * @event contextmenu
33240 * Fires when this node is right clicked
33241 * @param {Node} this This node
33242 * @param {Roo.EventObject} e The event object
33244 "contextmenu":true,
33246 * @event beforechildrenrendered
33247 * Fires right before the child nodes for this node are rendered
33248 * @param {Node} this This node
33250 "beforechildrenrendered":true
33253 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33256 * Read-only. The UI for this node
33259 this.ui = new uiClass(this);
33261 // finally support items[]
33262 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33267 Roo.each(this.attributes.items, function(c) {
33268 this.appendChild(Roo.factory(c,Roo.Tree));
33270 delete this.attributes.items;
33275 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33276 preventHScroll: true,
33278 * Returns true if this node is expanded
33279 * @return {Boolean}
33281 isExpanded : function(){
33282 return this.expanded;
33286 * Returns the UI object for this node
33287 * @return {TreeNodeUI}
33289 getUI : function(){
33293 // private override
33294 setFirstChild : function(node){
33295 var of = this.firstChild;
33296 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33297 if(this.childrenRendered && of && node != of){
33298 of.renderIndent(true, true);
33301 this.renderIndent(true, true);
33305 // private override
33306 setLastChild : function(node){
33307 var ol = this.lastChild;
33308 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33309 if(this.childrenRendered && ol && node != ol){
33310 ol.renderIndent(true, true);
33313 this.renderIndent(true, true);
33317 // these methods are overridden to provide lazy rendering support
33318 // private override
33319 appendChild : function()
33321 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33322 if(node && this.childrenRendered){
33325 this.ui.updateExpandIcon();
33329 // private override
33330 removeChild : function(node){
33331 this.ownerTree.getSelectionModel().unselect(node);
33332 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33333 // if it's been rendered remove dom node
33334 if(this.childrenRendered){
33337 if(this.childNodes.length < 1){
33338 this.collapse(false, false);
33340 this.ui.updateExpandIcon();
33342 if(!this.firstChild) {
33343 this.childrenRendered = false;
33348 // private override
33349 insertBefore : function(node, refNode){
33350 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33351 if(newNode && refNode && this.childrenRendered){
33354 this.ui.updateExpandIcon();
33359 * Sets the text for this node
33360 * @param {String} text
33362 setText : function(text){
33363 var oldText = this.text;
33365 this.attributes.text = text;
33366 if(this.rendered){ // event without subscribing
33367 this.ui.onTextChange(this, text, oldText);
33369 this.fireEvent("textchange", this, text, oldText);
33373 * Triggers selection of this node
33375 select : function(){
33376 this.getOwnerTree().getSelectionModel().select(this);
33380 * Triggers deselection of this node
33382 unselect : function(){
33383 this.getOwnerTree().getSelectionModel().unselect(this);
33387 * Returns true if this node is selected
33388 * @return {Boolean}
33390 isSelected : function(){
33391 return this.getOwnerTree().getSelectionModel().isSelected(this);
33395 * Expand this node.
33396 * @param {Boolean} deep (optional) True to expand all children as well
33397 * @param {Boolean} anim (optional) false to cancel the default animation
33398 * @param {Function} callback (optional) A callback to be called when
33399 * expanding this node completes (does not wait for deep expand to complete).
33400 * Called with 1 parameter, this node.
33402 expand : function(deep, anim, callback){
33403 if(!this.expanded){
33404 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33407 if(!this.childrenRendered){
33408 this.renderChildren();
33410 this.expanded = true;
33411 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33412 this.ui.animExpand(function(){
33413 this.fireEvent("expand", this);
33414 if(typeof callback == "function"){
33418 this.expandChildNodes(true);
33420 }.createDelegate(this));
33424 this.fireEvent("expand", this);
33425 if(typeof callback == "function"){
33430 if(typeof callback == "function"){
33435 this.expandChildNodes(true);
33439 isHiddenRoot : function(){
33440 return this.isRoot && !this.getOwnerTree().rootVisible;
33444 * Collapse this node.
33445 * @param {Boolean} deep (optional) True to collapse all children as well
33446 * @param {Boolean} anim (optional) false to cancel the default animation
33448 collapse : function(deep, anim){
33449 if(this.expanded && !this.isHiddenRoot()){
33450 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33453 this.expanded = false;
33454 if((this.getOwnerTree().animate && anim !== false) || anim){
33455 this.ui.animCollapse(function(){
33456 this.fireEvent("collapse", this);
33458 this.collapseChildNodes(true);
33460 }.createDelegate(this));
33463 this.ui.collapse();
33464 this.fireEvent("collapse", this);
33468 var cs = this.childNodes;
33469 for(var i = 0, len = cs.length; i < len; i++) {
33470 cs[i].collapse(true, false);
33476 delayedExpand : function(delay){
33477 if(!this.expandProcId){
33478 this.expandProcId = this.expand.defer(delay, this);
33483 cancelExpand : function(){
33484 if(this.expandProcId){
33485 clearTimeout(this.expandProcId);
33487 this.expandProcId = false;
33491 * Toggles expanded/collapsed state of the node
33493 toggle : function(){
33502 * Ensures all parent nodes are expanded
33504 ensureVisible : function(callback){
33505 var tree = this.getOwnerTree();
33506 tree.expandPath(this.parentNode.getPath(), false, function(){
33507 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33508 Roo.callback(callback);
33509 }.createDelegate(this));
33513 * Expand all child nodes
33514 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33516 expandChildNodes : function(deep){
33517 var cs = this.childNodes;
33518 for(var i = 0, len = cs.length; i < len; i++) {
33519 cs[i].expand(deep);
33524 * Collapse all child nodes
33525 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33527 collapseChildNodes : function(deep){
33528 var cs = this.childNodes;
33529 for(var i = 0, len = cs.length; i < len; i++) {
33530 cs[i].collapse(deep);
33535 * Disables this node
33537 disable : function(){
33538 this.disabled = true;
33540 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33541 this.ui.onDisableChange(this, true);
33543 this.fireEvent("disabledchange", this, true);
33547 * Enables this node
33549 enable : function(){
33550 this.disabled = false;
33551 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33552 this.ui.onDisableChange(this, false);
33554 this.fireEvent("disabledchange", this, false);
33558 renderChildren : function(suppressEvent){
33559 if(suppressEvent !== false){
33560 this.fireEvent("beforechildrenrendered", this);
33562 var cs = this.childNodes;
33563 for(var i = 0, len = cs.length; i < len; i++){
33564 cs[i].render(true);
33566 this.childrenRendered = true;
33570 sort : function(fn, scope){
33571 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33572 if(this.childrenRendered){
33573 var cs = this.childNodes;
33574 for(var i = 0, len = cs.length; i < len; i++){
33575 cs[i].render(true);
33581 render : function(bulkRender){
33582 this.ui.render(bulkRender);
33583 if(!this.rendered){
33584 this.rendered = true;
33586 this.expanded = false;
33587 this.expand(false, false);
33593 renderIndent : function(deep, refresh){
33595 this.ui.childIndent = null;
33597 this.ui.renderIndent();
33598 if(deep === true && this.childrenRendered){
33599 var cs = this.childNodes;
33600 for(var i = 0, len = cs.length; i < len; i++){
33601 cs[i].renderIndent(true, refresh);
33607 * Ext JS Library 1.1.1
33608 * Copyright(c) 2006-2007, Ext JS, LLC.
33610 * Originally Released Under LGPL - original licence link has changed is not relivant.
33613 * <script type="text/javascript">
33617 * @class Roo.tree.AsyncTreeNode
33618 * @extends Roo.tree.TreeNode
33619 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33621 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33623 Roo.tree.AsyncTreeNode = function(config){
33624 this.loaded = false;
33625 this.loading = false;
33626 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33628 * @event beforeload
33629 * Fires before this node is loaded, return false to cancel
33630 * @param {Node} this This node
33632 this.addEvents({'beforeload':true, 'load': true});
33635 * Fires when this node is loaded
33636 * @param {Node} this This node
33639 * The loader used by this node (defaults to using the tree's defined loader)
33644 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33645 expand : function(deep, anim, callback){
33646 if(this.loading){ // if an async load is already running, waiting til it's done
33648 var f = function(){
33649 if(!this.loading){ // done loading
33650 clearInterval(timer);
33651 this.expand(deep, anim, callback);
33653 }.createDelegate(this);
33654 timer = setInterval(f, 200);
33658 if(this.fireEvent("beforeload", this) === false){
33661 this.loading = true;
33662 this.ui.beforeLoad(this);
33663 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33665 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33669 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33673 * Returns true if this node is currently loading
33674 * @return {Boolean}
33676 isLoading : function(){
33677 return this.loading;
33680 loadComplete : function(deep, anim, callback){
33681 this.loading = false;
33682 this.loaded = true;
33683 this.ui.afterLoad(this);
33684 this.fireEvent("load", this);
33685 this.expand(deep, anim, callback);
33689 * Returns true if this node has been loaded
33690 * @return {Boolean}
33692 isLoaded : function(){
33693 return this.loaded;
33696 hasChildNodes : function(){
33697 if(!this.isLeaf() && !this.loaded){
33700 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33705 * Trigger a reload for this node
33706 * @param {Function} callback
33708 reload : function(callback){
33709 this.collapse(false, false);
33710 while(this.firstChild){
33711 this.removeChild(this.firstChild);
33713 this.childrenRendered = false;
33714 this.loaded = false;
33715 if(this.isHiddenRoot()){
33716 this.expanded = false;
33718 this.expand(false, false, callback);
33722 * Ext JS Library 1.1.1
33723 * Copyright(c) 2006-2007, Ext JS, LLC.
33725 * Originally Released Under LGPL - original licence link has changed is not relivant.
33728 * <script type="text/javascript">
33732 * @class Roo.tree.TreeNodeUI
33734 * @param {Object} node The node to render
33735 * The TreeNode UI implementation is separate from the
33736 * tree implementation. Unless you are customizing the tree UI,
33737 * you should never have to use this directly.
33739 Roo.tree.TreeNodeUI = function(node){
33741 this.rendered = false;
33742 this.animating = false;
33743 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33746 Roo.tree.TreeNodeUI.prototype = {
33747 removeChild : function(node){
33749 this.ctNode.removeChild(node.ui.getEl());
33753 beforeLoad : function(){
33754 this.addClass("x-tree-node-loading");
33757 afterLoad : function(){
33758 this.removeClass("x-tree-node-loading");
33761 onTextChange : function(node, text, oldText){
33763 this.textNode.innerHTML = text;
33767 onDisableChange : function(node, state){
33768 this.disabled = state;
33770 this.addClass("x-tree-node-disabled");
33772 this.removeClass("x-tree-node-disabled");
33776 onSelectedChange : function(state){
33779 this.addClass("x-tree-selected");
33782 this.removeClass("x-tree-selected");
33786 onMove : function(tree, node, oldParent, newParent, index, refNode){
33787 this.childIndent = null;
33789 var targetNode = newParent.ui.getContainer();
33790 if(!targetNode){//target not rendered
33791 this.holder = document.createElement("div");
33792 this.holder.appendChild(this.wrap);
33795 var insertBefore = refNode ? refNode.ui.getEl() : null;
33797 targetNode.insertBefore(this.wrap, insertBefore);
33799 targetNode.appendChild(this.wrap);
33801 this.node.renderIndent(true);
33805 addClass : function(cls){
33807 Roo.fly(this.elNode).addClass(cls);
33811 removeClass : function(cls){
33813 Roo.fly(this.elNode).removeClass(cls);
33817 remove : function(){
33819 this.holder = document.createElement("div");
33820 this.holder.appendChild(this.wrap);
33824 fireEvent : function(){
33825 return this.node.fireEvent.apply(this.node, arguments);
33828 initEvents : function(){
33829 this.node.on("move", this.onMove, this);
33830 var E = Roo.EventManager;
33831 var a = this.anchor;
33833 var el = Roo.fly(a, '_treeui');
33835 if(Roo.isOpera){ // opera render bug ignores the CSS
33836 el.setStyle("text-decoration", "none");
33839 el.on("click", this.onClick, this);
33840 el.on("dblclick", this.onDblClick, this);
33843 Roo.EventManager.on(this.checkbox,
33844 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33847 el.on("contextmenu", this.onContextMenu, this);
33849 var icon = Roo.fly(this.iconNode);
33850 icon.on("click", this.onClick, this);
33851 icon.on("dblclick", this.onDblClick, this);
33852 icon.on("contextmenu", this.onContextMenu, this);
33853 E.on(this.ecNode, "click", this.ecClick, this, true);
33855 if(this.node.disabled){
33856 this.addClass("x-tree-node-disabled");
33858 if(this.node.hidden){
33859 this.addClass("x-tree-node-disabled");
33861 var ot = this.node.getOwnerTree();
33862 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33863 if(dd && (!this.node.isRoot || ot.rootVisible)){
33864 Roo.dd.Registry.register(this.elNode, {
33866 handles: this.getDDHandles(),
33872 getDDHandles : function(){
33873 return [this.iconNode, this.textNode];
33878 this.wrap.style.display = "none";
33884 this.wrap.style.display = "";
33888 onContextMenu : function(e){
33889 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33890 e.preventDefault();
33892 this.fireEvent("contextmenu", this.node, e);
33896 onClick : function(e){
33901 if(this.fireEvent("beforeclick", this.node, e) !== false){
33902 if(!this.disabled && this.node.attributes.href){
33903 this.fireEvent("click", this.node, e);
33906 e.preventDefault();
33911 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33912 this.node.toggle();
33915 this.fireEvent("click", this.node, e);
33921 onDblClick : function(e){
33922 e.preventDefault();
33927 this.toggleCheck();
33929 if(!this.animating && this.node.hasChildNodes()){
33930 this.node.toggle();
33932 this.fireEvent("dblclick", this.node, e);
33935 onCheckChange : function(){
33936 var checked = this.checkbox.checked;
33937 this.node.attributes.checked = checked;
33938 this.fireEvent('checkchange', this.node, checked);
33941 ecClick : function(e){
33942 if(!this.animating && this.node.hasChildNodes()){
33943 this.node.toggle();
33947 startDrop : function(){
33948 this.dropping = true;
33951 // delayed drop so the click event doesn't get fired on a drop
33952 endDrop : function(){
33953 setTimeout(function(){
33954 this.dropping = false;
33955 }.createDelegate(this), 50);
33958 expand : function(){
33959 this.updateExpandIcon();
33960 this.ctNode.style.display = "";
33963 focus : function(){
33964 if(!this.node.preventHScroll){
33965 try{this.anchor.focus();
33967 }else if(!Roo.isIE){
33969 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33970 var l = noscroll.scrollLeft;
33971 this.anchor.focus();
33972 noscroll.scrollLeft = l;
33977 toggleCheck : function(value){
33978 var cb = this.checkbox;
33980 cb.checked = (value === undefined ? !cb.checked : value);
33986 this.anchor.blur();
33990 animExpand : function(callback){
33991 var ct = Roo.get(this.ctNode);
33993 if(!this.node.hasChildNodes()){
33994 this.updateExpandIcon();
33995 this.ctNode.style.display = "";
33996 Roo.callback(callback);
33999 this.animating = true;
34000 this.updateExpandIcon();
34003 callback : function(){
34004 this.animating = false;
34005 Roo.callback(callback);
34008 duration: this.node.ownerTree.duration || .25
34012 highlight : function(){
34013 var tree = this.node.getOwnerTree();
34014 Roo.fly(this.wrap).highlight(
34015 tree.hlColor || "C3DAF9",
34016 {endColor: tree.hlBaseColor}
34020 collapse : function(){
34021 this.updateExpandIcon();
34022 this.ctNode.style.display = "none";
34025 animCollapse : function(callback){
34026 var ct = Roo.get(this.ctNode);
34027 ct.enableDisplayMode('block');
34030 this.animating = true;
34031 this.updateExpandIcon();
34034 callback : function(){
34035 this.animating = false;
34036 Roo.callback(callback);
34039 duration: this.node.ownerTree.duration || .25
34043 getContainer : function(){
34044 return this.ctNode;
34047 getEl : function(){
34051 appendDDGhost : function(ghostNode){
34052 ghostNode.appendChild(this.elNode.cloneNode(true));
34055 getDDRepairXY : function(){
34056 return Roo.lib.Dom.getXY(this.iconNode);
34059 onRender : function(){
34063 render : function(bulkRender){
34064 var n = this.node, a = n.attributes;
34065 var targetNode = n.parentNode ?
34066 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34068 if(!this.rendered){
34069 this.rendered = true;
34071 this.renderElements(n, a, targetNode, bulkRender);
34074 if(this.textNode.setAttributeNS){
34075 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34077 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34080 this.textNode.setAttribute("ext:qtip", a.qtip);
34082 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34085 }else if(a.qtipCfg){
34086 a.qtipCfg.target = Roo.id(this.textNode);
34087 Roo.QuickTips.register(a.qtipCfg);
34090 if(!this.node.expanded){
34091 this.updateExpandIcon();
34094 if(bulkRender === true) {
34095 targetNode.appendChild(this.wrap);
34100 renderElements : function(n, a, targetNode, bulkRender)
34102 // add some indent caching, this helps performance when rendering a large tree
34103 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34104 var t = n.getOwnerTree();
34105 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34106 if (typeof(n.attributes.html) != 'undefined') {
34107 txt = n.attributes.html;
34109 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34110 var cb = typeof a.checked == 'boolean';
34111 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34112 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34113 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34114 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34115 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34116 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34117 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34118 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34119 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34120 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34123 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34124 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34125 n.nextSibling.ui.getEl(), buf.join(""));
34127 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34130 this.elNode = this.wrap.childNodes[0];
34131 this.ctNode = this.wrap.childNodes[1];
34132 var cs = this.elNode.childNodes;
34133 this.indentNode = cs[0];
34134 this.ecNode = cs[1];
34135 this.iconNode = cs[2];
34138 this.checkbox = cs[3];
34141 this.anchor = cs[index];
34142 this.textNode = cs[index].firstChild;
34145 getAnchor : function(){
34146 return this.anchor;
34149 getTextEl : function(){
34150 return this.textNode;
34153 getIconEl : function(){
34154 return this.iconNode;
34157 isChecked : function(){
34158 return this.checkbox ? this.checkbox.checked : false;
34161 updateExpandIcon : function(){
34163 var n = this.node, c1, c2;
34164 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34165 var hasChild = n.hasChildNodes();
34169 c1 = "x-tree-node-collapsed";
34170 c2 = "x-tree-node-expanded";
34173 c1 = "x-tree-node-expanded";
34174 c2 = "x-tree-node-collapsed";
34177 this.removeClass("x-tree-node-leaf");
34178 this.wasLeaf = false;
34180 if(this.c1 != c1 || this.c2 != c2){
34181 Roo.fly(this.elNode).replaceClass(c1, c2);
34182 this.c1 = c1; this.c2 = c2;
34185 // this changes non-leafs into leafs if they have no children.
34186 // it's not very rational behaviour..
34188 if(!this.wasLeaf && this.node.leaf){
34189 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34192 this.wasLeaf = true;
34195 var ecc = "x-tree-ec-icon "+cls;
34196 if(this.ecc != ecc){
34197 this.ecNode.className = ecc;
34203 getChildIndent : function(){
34204 if(!this.childIndent){
34208 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34210 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34212 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34217 this.childIndent = buf.join("");
34219 return this.childIndent;
34222 renderIndent : function(){
34225 var p = this.node.parentNode;
34227 indent = p.ui.getChildIndent();
34229 if(this.indentMarkup != indent){ // don't rerender if not required
34230 this.indentNode.innerHTML = indent;
34231 this.indentMarkup = indent;
34233 this.updateExpandIcon();
34238 Roo.tree.RootTreeNodeUI = function(){
34239 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34241 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34242 render : function(){
34243 if(!this.rendered){
34244 var targetNode = this.node.ownerTree.innerCt.dom;
34245 this.node.expanded = true;
34246 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34247 this.wrap = this.ctNode = targetNode.firstChild;
34250 collapse : function(){
34252 expand : function(){
34256 * Ext JS Library 1.1.1
34257 * Copyright(c) 2006-2007, Ext JS, LLC.
34259 * Originally Released Under LGPL - original licence link has changed is not relivant.
34262 * <script type="text/javascript">
34265 * @class Roo.tree.TreeLoader
34266 * @extends Roo.util.Observable
34267 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34268 * nodes from a specified URL. The response must be a javascript Array definition
34269 * who's elements are node definition objects. eg:
34274 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34275 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34282 * The old style respose with just an array is still supported, but not recommended.
34285 * A server request is sent, and child nodes are loaded only when a node is expanded.
34286 * The loading node's id is passed to the server under the parameter name "node" to
34287 * enable the server to produce the correct child nodes.
34289 * To pass extra parameters, an event handler may be attached to the "beforeload"
34290 * event, and the parameters specified in the TreeLoader's baseParams property:
34292 myTreeLoader.on("beforeload", function(treeLoader, node) {
34293 this.baseParams.category = node.attributes.category;
34296 * This would pass an HTTP parameter called "category" to the server containing
34297 * the value of the Node's "category" attribute.
34299 * Creates a new Treeloader.
34300 * @param {Object} config A config object containing config properties.
34302 Roo.tree.TreeLoader = function(config){
34303 this.baseParams = {};
34304 this.requestMethod = "POST";
34305 Roo.apply(this, config);
34310 * @event beforeload
34311 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34312 * @param {Object} This TreeLoader object.
34313 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34314 * @param {Object} callback The callback function specified in the {@link #load} call.
34319 * Fires when the node has been successfuly loaded.
34320 * @param {Object} This TreeLoader object.
34321 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34322 * @param {Object} response The response object containing the data from the server.
34326 * @event loadexception
34327 * Fires if the network request failed.
34328 * @param {Object} This TreeLoader object.
34329 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34330 * @param {Object} response The response object containing the data from the server.
34332 loadexception : true,
34335 * Fires before a node is created, enabling you to return custom Node types
34336 * @param {Object} This TreeLoader object.
34337 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34342 Roo.tree.TreeLoader.superclass.constructor.call(this);
34345 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34347 * @cfg {String} dataUrl The URL from which to request a Json string which
34348 * specifies an array of node definition object representing the child nodes
34352 * @cfg {String} requestMethod either GET or POST
34353 * defaults to POST (due to BC)
34357 * @cfg {Object} baseParams (optional) An object containing properties which
34358 * specify HTTP parameters to be passed to each request for child nodes.
34361 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34362 * created by this loader. If the attributes sent by the server have an attribute in this object,
34363 * they take priority.
34366 * @cfg {Object} uiProviders (optional) An object containing properties which
34368 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34369 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34370 * <i>uiProvider</i> attribute of a returned child node is a string rather
34371 * than a reference to a TreeNodeUI implementation, this that string value
34372 * is used as a property name in the uiProviders object. You can define the provider named
34373 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34378 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34379 * child nodes before loading.
34381 clearOnLoad : true,
34384 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34385 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34386 * Grid query { data : [ .....] }
34391 * @cfg {String} queryParam (optional)
34392 * Name of the query as it will be passed on the querystring (defaults to 'node')
34393 * eg. the request will be ?node=[id]
34400 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34401 * This is called automatically when a node is expanded, but may be used to reload
34402 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34403 * @param {Roo.tree.TreeNode} node
34404 * @param {Function} callback
34406 load : function(node, callback){
34407 if(this.clearOnLoad){
34408 while(node.firstChild){
34409 node.removeChild(node.firstChild);
34412 if(node.attributes.children){ // preloaded json children
34413 var cs = node.attributes.children;
34414 for(var i = 0, len = cs.length; i < len; i++){
34415 node.appendChild(this.createNode(cs[i]));
34417 if(typeof callback == "function"){
34420 }else if(this.dataUrl){
34421 this.requestData(node, callback);
34425 getParams: function(node){
34426 var buf = [], bp = this.baseParams;
34427 for(var key in bp){
34428 if(typeof bp[key] != "function"){
34429 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34432 var n = this.queryParam === false ? 'node' : this.queryParam;
34433 buf.push(n + "=", encodeURIComponent(node.id));
34434 return buf.join("");
34437 requestData : function(node, callback){
34438 if(this.fireEvent("beforeload", this, node, callback) !== false){
34439 this.transId = Roo.Ajax.request({
34440 method:this.requestMethod,
34441 url: this.dataUrl||this.url,
34442 success: this.handleResponse,
34443 failure: this.handleFailure,
34445 argument: {callback: callback, node: node},
34446 params: this.getParams(node)
34449 // if the load is cancelled, make sure we notify
34450 // the node that we are done
34451 if(typeof callback == "function"){
34457 isLoading : function(){
34458 return this.transId ? true : false;
34461 abort : function(){
34462 if(this.isLoading()){
34463 Roo.Ajax.abort(this.transId);
34468 createNode : function(attr)
34470 // apply baseAttrs, nice idea Corey!
34471 if(this.baseAttrs){
34472 Roo.applyIf(attr, this.baseAttrs);
34474 if(this.applyLoader !== false){
34475 attr.loader = this;
34477 // uiProvider = depreciated..
34479 if(typeof(attr.uiProvider) == 'string'){
34480 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34481 /** eval:var:attr */ eval(attr.uiProvider);
34483 if(typeof(this.uiProviders['default']) != 'undefined') {
34484 attr.uiProvider = this.uiProviders['default'];
34487 this.fireEvent('create', this, attr);
34489 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34491 new Roo.tree.TreeNode(attr) :
34492 new Roo.tree.AsyncTreeNode(attr));
34495 processResponse : function(response, node, callback)
34497 var json = response.responseText;
34500 var o = Roo.decode(json);
34502 if (this.root === false && typeof(o.success) != undefined) {
34503 this.root = 'data'; // the default behaviour for list like data..
34506 if (this.root !== false && !o.success) {
34507 // it's a failure condition.
34508 var a = response.argument;
34509 this.fireEvent("loadexception", this, a.node, response);
34510 Roo.log("Load failed - should have a handler really");
34516 if (this.root !== false) {
34520 for(var i = 0, len = o.length; i < len; i++){
34521 var n = this.createNode(o[i]);
34523 node.appendChild(n);
34526 if(typeof callback == "function"){
34527 callback(this, node);
34530 this.handleFailure(response);
34534 handleResponse : function(response){
34535 this.transId = false;
34536 var a = response.argument;
34537 this.processResponse(response, a.node, a.callback);
34538 this.fireEvent("load", this, a.node, response);
34541 handleFailure : function(response)
34543 // should handle failure better..
34544 this.transId = false;
34545 var a = response.argument;
34546 this.fireEvent("loadexception", this, a.node, response);
34547 if(typeof a.callback == "function"){
34548 a.callback(this, a.node);
34553 * Ext JS Library 1.1.1
34554 * Copyright(c) 2006-2007, Ext JS, LLC.
34556 * Originally Released Under LGPL - original licence link has changed is not relivant.
34559 * <script type="text/javascript">
34563 * @class Roo.tree.TreeFilter
34564 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34565 * @param {TreePanel} tree
34566 * @param {Object} config (optional)
34568 Roo.tree.TreeFilter = function(tree, config){
34570 this.filtered = {};
34571 Roo.apply(this, config);
34574 Roo.tree.TreeFilter.prototype = {
34581 * Filter the data by a specific attribute.
34582 * @param {String/RegExp} value Either string that the attribute value
34583 * should start with or a RegExp to test against the attribute
34584 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34585 * @param {TreeNode} startNode (optional) The node to start the filter at.
34587 filter : function(value, attr, startNode){
34588 attr = attr || "text";
34590 if(typeof value == "string"){
34591 var vlen = value.length;
34592 // auto clear empty filter
34593 if(vlen == 0 && this.clearBlank){
34597 value = value.toLowerCase();
34599 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34601 }else if(value.exec){ // regex?
34603 return value.test(n.attributes[attr]);
34606 throw 'Illegal filter type, must be string or regex';
34608 this.filterBy(f, null, startNode);
34612 * Filter by a function. The passed function will be called with each
34613 * node in the tree (or from the startNode). If the function returns true, the node is kept
34614 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34615 * @param {Function} fn The filter function
34616 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34618 filterBy : function(fn, scope, startNode){
34619 startNode = startNode || this.tree.root;
34620 if(this.autoClear){
34623 var af = this.filtered, rv = this.reverse;
34624 var f = function(n){
34625 if(n == startNode){
34631 var m = fn.call(scope || n, n);
34639 startNode.cascade(f);
34642 if(typeof id != "function"){
34644 if(n && n.parentNode){
34645 n.parentNode.removeChild(n);
34653 * Clears the current filter. Note: with the "remove" option
34654 * set a filter cannot be cleared.
34656 clear : function(){
34658 var af = this.filtered;
34660 if(typeof id != "function"){
34667 this.filtered = {};
34672 * Ext JS Library 1.1.1
34673 * Copyright(c) 2006-2007, Ext JS, LLC.
34675 * Originally Released Under LGPL - original licence link has changed is not relivant.
34678 * <script type="text/javascript">
34683 * @class Roo.tree.TreeSorter
34684 * Provides sorting of nodes in a TreePanel
34686 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34687 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34688 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34689 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34690 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34691 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34693 * @param {TreePanel} tree
34694 * @param {Object} config
34696 Roo.tree.TreeSorter = function(tree, config){
34697 Roo.apply(this, config);
34698 tree.on("beforechildrenrendered", this.doSort, this);
34699 tree.on("append", this.updateSort, this);
34700 tree.on("insert", this.updateSort, this);
34702 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34703 var p = this.property || "text";
34704 var sortType = this.sortType;
34705 var fs = this.folderSort;
34706 var cs = this.caseSensitive === true;
34707 var leafAttr = this.leafAttr || 'leaf';
34709 this.sortFn = function(n1, n2){
34711 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34714 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34718 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34719 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34721 return dsc ? +1 : -1;
34723 return dsc ? -1 : +1;
34730 Roo.tree.TreeSorter.prototype = {
34731 doSort : function(node){
34732 node.sort(this.sortFn);
34735 compareNodes : function(n1, n2){
34736 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34739 updateSort : function(tree, node){
34740 if(node.childrenRendered){
34741 this.doSort.defer(1, this, [node]);
34746 * Ext JS Library 1.1.1
34747 * Copyright(c) 2006-2007, Ext JS, LLC.
34749 * Originally Released Under LGPL - original licence link has changed is not relivant.
34752 * <script type="text/javascript">
34755 if(Roo.dd.DropZone){
34757 Roo.tree.TreeDropZone = function(tree, config){
34758 this.allowParentInsert = false;
34759 this.allowContainerDrop = false;
34760 this.appendOnly = false;
34761 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34763 this.lastInsertClass = "x-tree-no-status";
34764 this.dragOverData = {};
34767 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34768 ddGroup : "TreeDD",
34771 expandDelay : 1000,
34773 expandNode : function(node){
34774 if(node.hasChildNodes() && !node.isExpanded()){
34775 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34779 queueExpand : function(node){
34780 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34783 cancelExpand : function(){
34784 if(this.expandProcId){
34785 clearTimeout(this.expandProcId);
34786 this.expandProcId = false;
34790 isValidDropPoint : function(n, pt, dd, e, data){
34791 if(!n || !data){ return false; }
34792 var targetNode = n.node;
34793 var dropNode = data.node;
34794 // default drop rules
34795 if(!(targetNode && targetNode.isTarget && pt)){
34798 if(pt == "append" && targetNode.allowChildren === false){
34801 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34804 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34807 // reuse the object
34808 var overEvent = this.dragOverData;
34809 overEvent.tree = this.tree;
34810 overEvent.target = targetNode;
34811 overEvent.data = data;
34812 overEvent.point = pt;
34813 overEvent.source = dd;
34814 overEvent.rawEvent = e;
34815 overEvent.dropNode = dropNode;
34816 overEvent.cancel = false;
34817 var result = this.tree.fireEvent("nodedragover", overEvent);
34818 return overEvent.cancel === false && result !== false;
34821 getDropPoint : function(e, n, dd)
34825 return tn.allowChildren !== false ? "append" : false; // always append for root
34827 var dragEl = n.ddel;
34828 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34829 var y = Roo.lib.Event.getPageY(e);
34830 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34832 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34833 var noAppend = tn.allowChildren === false;
34834 if(this.appendOnly || tn.parentNode.allowChildren === false){
34835 return noAppend ? false : "append";
34837 var noBelow = false;
34838 if(!this.allowParentInsert){
34839 noBelow = tn.hasChildNodes() && tn.isExpanded();
34841 var q = (b - t) / (noAppend ? 2 : 3);
34842 if(y >= t && y < (t + q)){
34844 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34851 onNodeEnter : function(n, dd, e, data)
34853 this.cancelExpand();
34856 onNodeOver : function(n, dd, e, data)
34859 var pt = this.getDropPoint(e, n, dd);
34862 // auto node expand check
34863 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34864 this.queueExpand(node);
34865 }else if(pt != "append"){
34866 this.cancelExpand();
34869 // set the insert point style on the target node
34870 var returnCls = this.dropNotAllowed;
34871 if(this.isValidDropPoint(n, pt, dd, e, data)){
34876 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34877 cls = "x-tree-drag-insert-above";
34878 }else if(pt == "below"){
34879 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34880 cls = "x-tree-drag-insert-below";
34882 returnCls = "x-tree-drop-ok-append";
34883 cls = "x-tree-drag-append";
34885 if(this.lastInsertClass != cls){
34886 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34887 this.lastInsertClass = cls;
34894 onNodeOut : function(n, dd, e, data){
34896 this.cancelExpand();
34897 this.removeDropIndicators(n);
34900 onNodeDrop : function(n, dd, e, data){
34901 var point = this.getDropPoint(e, n, dd);
34902 var targetNode = n.node;
34903 targetNode.ui.startDrop();
34904 if(!this.isValidDropPoint(n, point, dd, e, data)){
34905 targetNode.ui.endDrop();
34908 // first try to find the drop node
34909 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34912 target: targetNode,
34917 dropNode: dropNode,
34920 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34921 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34922 targetNode.ui.endDrop();
34925 // allow target changing
34926 targetNode = dropEvent.target;
34927 if(point == "append" && !targetNode.isExpanded()){
34928 targetNode.expand(false, null, function(){
34929 this.completeDrop(dropEvent);
34930 }.createDelegate(this));
34932 this.completeDrop(dropEvent);
34937 completeDrop : function(de){
34938 var ns = de.dropNode, p = de.point, t = de.target;
34939 if(!(ns instanceof Array)){
34943 for(var i = 0, len = ns.length; i < len; i++){
34946 t.parentNode.insertBefore(n, t);
34947 }else if(p == "below"){
34948 t.parentNode.insertBefore(n, t.nextSibling);
34954 if(this.tree.hlDrop){
34958 this.tree.fireEvent("nodedrop", de);
34961 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34962 if(this.tree.hlDrop){
34963 dropNode.ui.focus();
34964 dropNode.ui.highlight();
34966 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34969 getTree : function(){
34973 removeDropIndicators : function(n){
34976 Roo.fly(el).removeClass([
34977 "x-tree-drag-insert-above",
34978 "x-tree-drag-insert-below",
34979 "x-tree-drag-append"]);
34980 this.lastInsertClass = "_noclass";
34984 beforeDragDrop : function(target, e, id){
34985 this.cancelExpand();
34989 afterRepair : function(data){
34990 if(data && Roo.enableFx){
34991 data.node.ui.highlight();
35001 * Ext JS Library 1.1.1
35002 * Copyright(c) 2006-2007, Ext JS, LLC.
35004 * Originally Released Under LGPL - original licence link has changed is not relivant.
35007 * <script type="text/javascript">
35011 if(Roo.dd.DragZone){
35012 Roo.tree.TreeDragZone = function(tree, config){
35013 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
35017 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
35018 ddGroup : "TreeDD",
35020 onBeforeDrag : function(data, e){
35022 return n && n.draggable && !n.disabled;
35026 onInitDrag : function(e){
35027 var data = this.dragData;
35028 this.tree.getSelectionModel().select(data.node);
35029 this.proxy.update("");
35030 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
35031 this.tree.fireEvent("startdrag", this.tree, data.node, e);
35034 getRepairXY : function(e, data){
35035 return data.node.ui.getDDRepairXY();
35038 onEndDrag : function(data, e){
35039 this.tree.fireEvent("enddrag", this.tree, data.node, e);
35044 onValidDrop : function(dd, e, id){
35045 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
35049 beforeInvalidDrop : function(e, id){
35050 // this scrolls the original position back into view
35051 var sm = this.tree.getSelectionModel();
35052 sm.clearSelections();
35053 sm.select(this.dragData.node);
35058 * Ext JS Library 1.1.1
35059 * Copyright(c) 2006-2007, Ext JS, LLC.
35061 * Originally Released Under LGPL - original licence link has changed is not relivant.
35064 * <script type="text/javascript">
35067 * @class Roo.tree.TreeEditor
35068 * @extends Roo.Editor
35069 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35070 * as the editor field.
35072 * @param {Object} config (used to be the tree panel.)
35073 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35075 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35076 * @cfg {Roo.form.TextField|Object} field The field configuration
35080 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35083 if (oldconfig) { // old style..
35084 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35087 tree = config.tree;
35088 config.field = config.field || {};
35089 config.field.xtype = 'TextField';
35090 field = Roo.factory(config.field, Roo.form);
35092 config = config || {};
35097 * @event beforenodeedit
35098 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35099 * false from the handler of this event.
35100 * @param {Editor} this
35101 * @param {Roo.tree.Node} node
35103 "beforenodeedit" : true
35107 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35111 tree.on('beforeclick', this.beforeNodeClick, this);
35112 tree.getTreeEl().on('mousedown', this.hide, this);
35113 this.on('complete', this.updateNode, this);
35114 this.on('beforestartedit', this.fitToTree, this);
35115 this.on('startedit', this.bindScroll, this, {delay:10});
35116 this.on('specialkey', this.onSpecialKey, this);
35119 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35121 * @cfg {String} alignment
35122 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35128 * @cfg {Boolean} hideEl
35129 * True to hide the bound element while the editor is displayed (defaults to false)
35133 * @cfg {String} cls
35134 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35136 cls: "x-small-editor x-tree-editor",
35138 * @cfg {Boolean} shim
35139 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35145 * @cfg {Number} maxWidth
35146 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35147 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35148 * scroll and client offsets into account prior to each edit.
35155 fitToTree : function(ed, el){
35156 var td = this.tree.getTreeEl().dom, nd = el.dom;
35157 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35158 td.scrollLeft = nd.offsetLeft;
35162 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35163 this.setSize(w, '');
35165 return this.fireEvent('beforenodeedit', this, this.editNode);
35170 triggerEdit : function(node){
35171 this.completeEdit();
35172 this.editNode = node;
35173 this.startEdit(node.ui.textNode, node.text);
35177 bindScroll : function(){
35178 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35182 beforeNodeClick : function(node, e){
35183 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35184 this.lastClick = new Date();
35185 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35187 this.triggerEdit(node);
35194 updateNode : function(ed, value){
35195 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35196 this.editNode.setText(value);
35200 onHide : function(){
35201 Roo.tree.TreeEditor.superclass.onHide.call(this);
35203 this.editNode.ui.focus();
35208 onSpecialKey : function(field, e){
35209 var k = e.getKey();
35213 }else if(k == e.ENTER && !e.hasModifier()){
35215 this.completeEdit();
35218 });//<Script type="text/javascript">
35221 * Ext JS Library 1.1.1
35222 * Copyright(c) 2006-2007, Ext JS, LLC.
35224 * Originally Released Under LGPL - original licence link has changed is not relivant.
35227 * <script type="text/javascript">
35231 * Not documented??? - probably should be...
35234 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35235 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35237 renderElements : function(n, a, targetNode, bulkRender){
35238 //consel.log("renderElements?");
35239 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35241 var t = n.getOwnerTree();
35242 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35244 var cols = t.columns;
35245 var bw = t.borderWidth;
35247 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35248 var cb = typeof a.checked == "boolean";
35249 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35250 var colcls = 'x-t-' + tid + '-c0';
35252 '<li class="x-tree-node">',
35255 '<div class="x-tree-node-el ', a.cls,'">',
35257 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35260 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35261 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35262 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35263 (a.icon ? ' x-tree-node-inline-icon' : ''),
35264 (a.iconCls ? ' '+a.iconCls : ''),
35265 '" unselectable="on" />',
35266 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35267 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35269 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35270 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35271 '<span unselectable="on" qtip="' + tx + '">',
35275 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35276 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35278 for(var i = 1, len = cols.length; i < len; i++){
35280 colcls = 'x-t-' + tid + '-c' +i;
35281 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35282 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35283 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35289 '<div class="x-clear"></div></div>',
35290 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35293 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35294 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35295 n.nextSibling.ui.getEl(), buf.join(""));
35297 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35299 var el = this.wrap.firstChild;
35301 this.elNode = el.firstChild;
35302 this.ranchor = el.childNodes[1];
35303 this.ctNode = this.wrap.childNodes[1];
35304 var cs = el.firstChild.childNodes;
35305 this.indentNode = cs[0];
35306 this.ecNode = cs[1];
35307 this.iconNode = cs[2];
35310 this.checkbox = cs[3];
35313 this.anchor = cs[index];
35315 this.textNode = cs[index].firstChild;
35317 //el.on("click", this.onClick, this);
35318 //el.on("dblclick", this.onDblClick, this);
35321 // console.log(this);
35323 initEvents : function(){
35324 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35327 var a = this.ranchor;
35329 var el = Roo.get(a);
35331 if(Roo.isOpera){ // opera render bug ignores the CSS
35332 el.setStyle("text-decoration", "none");
35335 el.on("click", this.onClick, this);
35336 el.on("dblclick", this.onDblClick, this);
35337 el.on("contextmenu", this.onContextMenu, this);
35341 /*onSelectedChange : function(state){
35344 this.addClass("x-tree-selected");
35347 this.removeClass("x-tree-selected");
35350 addClass : function(cls){
35352 Roo.fly(this.elRow).addClass(cls);
35358 removeClass : function(cls){
35360 Roo.fly(this.elRow).removeClass(cls);
35366 });//<Script type="text/javascript">
35370 * Ext JS Library 1.1.1
35371 * Copyright(c) 2006-2007, Ext JS, LLC.
35373 * Originally Released Under LGPL - original licence link has changed is not relivant.
35376 * <script type="text/javascript">
35381 * @class Roo.tree.ColumnTree
35382 * @extends Roo.data.TreePanel
35383 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35384 * @cfg {int} borderWidth compined right/left border allowance
35386 * @param {String/HTMLElement/Element} el The container element
35387 * @param {Object} config
35389 Roo.tree.ColumnTree = function(el, config)
35391 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35395 * Fire this event on a container when it resizes
35396 * @param {int} w Width
35397 * @param {int} h Height
35401 this.on('resize', this.onResize, this);
35404 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35408 borderWidth: Roo.isBorderBox ? 0 : 2,
35411 render : function(){
35412 // add the header.....
35414 Roo.tree.ColumnTree.superclass.render.apply(this);
35416 this.el.addClass('x-column-tree');
35418 this.headers = this.el.createChild(
35419 {cls:'x-tree-headers'},this.innerCt.dom);
35421 var cols = this.columns, c;
35422 var totalWidth = 0;
35424 var len = cols.length;
35425 for(var i = 0; i < len; i++){
35427 totalWidth += c.width;
35428 this.headEls.push(this.headers.createChild({
35429 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35431 cls:'x-tree-hd-text',
35434 style:'width:'+(c.width-this.borderWidth)+'px;'
35437 this.headers.createChild({cls:'x-clear'});
35438 // prevent floats from wrapping when clipped
35439 this.headers.setWidth(totalWidth);
35440 //this.innerCt.setWidth(totalWidth);
35441 this.innerCt.setStyle({ overflow: 'auto' });
35442 this.onResize(this.width, this.height);
35446 onResize : function(w,h)
35451 this.innerCt.setWidth(this.width);
35452 this.innerCt.setHeight(this.height-20);
35455 var cols = this.columns, c;
35456 var totalWidth = 0;
35458 var len = cols.length;
35459 for(var i = 0; i < len; i++){
35461 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35462 // it's the expander..
35463 expEl = this.headEls[i];
35466 totalWidth += c.width;
35470 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35472 this.headers.setWidth(w-20);
35481 * Ext JS Library 1.1.1
35482 * Copyright(c) 2006-2007, Ext JS, LLC.
35484 * Originally Released Under LGPL - original licence link has changed is not relivant.
35487 * <script type="text/javascript">
35491 * @class Roo.menu.Menu
35492 * @extends Roo.util.Observable
35493 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35494 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35496 * Creates a new Menu
35497 * @param {Object} config Configuration options
35499 Roo.menu.Menu = function(config){
35500 Roo.apply(this, config);
35501 this.id = this.id || Roo.id();
35504 * @event beforeshow
35505 * Fires before this menu is displayed
35506 * @param {Roo.menu.Menu} this
35510 * @event beforehide
35511 * Fires before this menu is hidden
35512 * @param {Roo.menu.Menu} this
35517 * Fires after this menu is displayed
35518 * @param {Roo.menu.Menu} this
35523 * Fires after this menu is hidden
35524 * @param {Roo.menu.Menu} this
35529 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35530 * @param {Roo.menu.Menu} this
35531 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35532 * @param {Roo.EventObject} e
35537 * Fires when the mouse is hovering over this menu
35538 * @param {Roo.menu.Menu} this
35539 * @param {Roo.EventObject} e
35540 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35545 * Fires when the mouse exits this menu
35546 * @param {Roo.menu.Menu} this
35547 * @param {Roo.EventObject} e
35548 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35553 * Fires when a menu item contained in this menu is clicked
35554 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35555 * @param {Roo.EventObject} e
35559 if (this.registerMenu) {
35560 Roo.menu.MenuMgr.register(this);
35563 var mis = this.items;
35564 this.items = new Roo.util.MixedCollection();
35566 this.add.apply(this, mis);
35570 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35572 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35576 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35577 * for bottom-right shadow (defaults to "sides")
35581 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35582 * this menu (defaults to "tl-tr?")
35584 subMenuAlign : "tl-tr?",
35586 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35587 * relative to its element of origin (defaults to "tl-bl?")
35589 defaultAlign : "tl-bl?",
35591 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35593 allowOtherMenus : false,
35595 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35597 registerMenu : true,
35602 render : function(){
35606 var el = this.el = new Roo.Layer({
35608 shadow:this.shadow,
35610 parentEl: this.parentEl || document.body,
35614 this.keyNav = new Roo.menu.MenuNav(this);
35617 el.addClass("x-menu-plain");
35620 el.addClass(this.cls);
35622 // generic focus element
35623 this.focusEl = el.createChild({
35624 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35626 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35627 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35629 ul.on("mouseover", this.onMouseOver, this);
35630 ul.on("mouseout", this.onMouseOut, this);
35631 this.items.each(function(item){
35636 var li = document.createElement("li");
35637 li.className = "x-menu-list-item";
35638 ul.dom.appendChild(li);
35639 item.render(li, this);
35646 autoWidth : function(){
35647 var el = this.el, ul = this.ul;
35651 var w = this.width;
35654 }else if(Roo.isIE){
35655 el.setWidth(this.minWidth);
35656 var t = el.dom.offsetWidth; // force recalc
35657 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35662 delayAutoWidth : function(){
35665 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35667 this.awTask.delay(20);
35672 findTargetItem : function(e){
35673 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35674 if(t && t.menuItemId){
35675 return this.items.get(t.menuItemId);
35680 onClick : function(e){
35681 Roo.log("menu.onClick");
35682 var t = this.findTargetItem(e);
35687 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35688 if(t == this.activeItem && t.shouldDeactivate(e)){
35689 this.activeItem.deactivate();
35690 delete this.activeItem;
35694 this.setActiveItem(t, true);
35702 this.fireEvent("click", this, t, e);
35706 setActiveItem : function(item, autoExpand){
35707 if(item != this.activeItem){
35708 if(this.activeItem){
35709 this.activeItem.deactivate();
35711 this.activeItem = item;
35712 item.activate(autoExpand);
35713 }else if(autoExpand){
35719 tryActivate : function(start, step){
35720 var items = this.items;
35721 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35722 var item = items.get(i);
35723 if(!item.disabled && item.canActivate){
35724 this.setActiveItem(item, false);
35732 onMouseOver : function(e){
35734 if(t = this.findTargetItem(e)){
35735 if(t.canActivate && !t.disabled){
35736 this.setActiveItem(t, true);
35739 this.fireEvent("mouseover", this, e, t);
35743 onMouseOut : function(e){
35745 if(t = this.findTargetItem(e)){
35746 if(t == this.activeItem && t.shouldDeactivate(e)){
35747 this.activeItem.deactivate();
35748 delete this.activeItem;
35751 this.fireEvent("mouseout", this, e, t);
35755 * Read-only. Returns true if the menu is currently displayed, else false.
35758 isVisible : function(){
35759 return this.el && !this.hidden;
35763 * Displays this menu relative to another element
35764 * @param {String/HTMLElement/Roo.Element} element The element to align to
35765 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35766 * the element (defaults to this.defaultAlign)
35767 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35769 show : function(el, pos, parentMenu){
35770 this.parentMenu = parentMenu;
35774 this.fireEvent("beforeshow", this);
35775 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35779 * Displays this menu at a specific xy position
35780 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35781 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35783 showAt : function(xy, parentMenu, /* private: */_e){
35784 this.parentMenu = parentMenu;
35789 this.fireEvent("beforeshow", this);
35790 xy = this.el.adjustForConstraints(xy);
35794 this.hidden = false;
35796 this.fireEvent("show", this);
35799 focus : function(){
35801 this.doFocus.defer(50, this);
35805 doFocus : function(){
35807 this.focusEl.focus();
35812 * Hides this menu and optionally all parent menus
35813 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35815 hide : function(deep){
35816 if(this.el && this.isVisible()){
35817 this.fireEvent("beforehide", this);
35818 if(this.activeItem){
35819 this.activeItem.deactivate();
35820 this.activeItem = null;
35823 this.hidden = true;
35824 this.fireEvent("hide", this);
35826 if(deep === true && this.parentMenu){
35827 this.parentMenu.hide(true);
35832 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35833 * Any of the following are valid:
35835 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35836 * <li>An HTMLElement object which will be converted to a menu item</li>
35837 * <li>A menu item config object that will be created as a new menu item</li>
35838 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35839 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35844 var menu = new Roo.menu.Menu();
35846 // Create a menu item to add by reference
35847 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35849 // Add a bunch of items at once using different methods.
35850 // Only the last item added will be returned.
35851 var item = menu.add(
35852 menuItem, // add existing item by ref
35853 'Dynamic Item', // new TextItem
35854 '-', // new separator
35855 { text: 'Config Item' } // new item by config
35858 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35859 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35862 var a = arguments, l = a.length, item;
35863 for(var i = 0; i < l; i++){
35865 if ((typeof(el) == "object") && el.xtype && el.xns) {
35866 el = Roo.factory(el, Roo.menu);
35869 if(el.render){ // some kind of Item
35870 item = this.addItem(el);
35871 }else if(typeof el == "string"){ // string
35872 if(el == "separator" || el == "-"){
35873 item = this.addSeparator();
35875 item = this.addText(el);
35877 }else if(el.tagName || el.el){ // element
35878 item = this.addElement(el);
35879 }else if(typeof el == "object"){ // must be menu item config?
35880 item = this.addMenuItem(el);
35887 * Returns this menu's underlying {@link Roo.Element} object
35888 * @return {Roo.Element} The element
35890 getEl : function(){
35898 * Adds a separator bar to the menu
35899 * @return {Roo.menu.Item} The menu item that was added
35901 addSeparator : function(){
35902 return this.addItem(new Roo.menu.Separator());
35906 * Adds an {@link Roo.Element} object to the menu
35907 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35908 * @return {Roo.menu.Item} The menu item that was added
35910 addElement : function(el){
35911 return this.addItem(new Roo.menu.BaseItem(el));
35915 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35916 * @param {Roo.menu.Item} item The menu item to add
35917 * @return {Roo.menu.Item} The menu item that was added
35919 addItem : function(item){
35920 this.items.add(item);
35922 var li = document.createElement("li");
35923 li.className = "x-menu-list-item";
35924 this.ul.dom.appendChild(li);
35925 item.render(li, this);
35926 this.delayAutoWidth();
35932 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35933 * @param {Object} config A MenuItem config object
35934 * @return {Roo.menu.Item} The menu item that was added
35936 addMenuItem : function(config){
35937 if(!(config instanceof Roo.menu.Item)){
35938 if(typeof config.checked == "boolean"){ // must be check menu item config?
35939 config = new Roo.menu.CheckItem(config);
35941 config = new Roo.menu.Item(config);
35944 return this.addItem(config);
35948 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35949 * @param {String} text The text to display in the menu item
35950 * @return {Roo.menu.Item} The menu item that was added
35952 addText : function(text){
35953 return this.addItem(new Roo.menu.TextItem({ text : text }));
35957 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35958 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35959 * @param {Roo.menu.Item} item The menu item to add
35960 * @return {Roo.menu.Item} The menu item that was added
35962 insert : function(index, item){
35963 this.items.insert(index, item);
35965 var li = document.createElement("li");
35966 li.className = "x-menu-list-item";
35967 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35968 item.render(li, this);
35969 this.delayAutoWidth();
35975 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35976 * @param {Roo.menu.Item} item The menu item to remove
35978 remove : function(item){
35979 this.items.removeKey(item.id);
35984 * Removes and destroys all items in the menu
35986 removeAll : function(){
35988 while(f = this.items.first()){
35994 // MenuNav is a private utility class used internally by the Menu
35995 Roo.menu.MenuNav = function(menu){
35996 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35997 this.scope = this.menu = menu;
36000 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
36001 doRelay : function(e, h){
36002 var k = e.getKey();
36003 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
36004 this.menu.tryActivate(0, 1);
36007 return h.call(this.scope || this, e, this.menu);
36010 up : function(e, m){
36011 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
36012 m.tryActivate(m.items.length-1, -1);
36016 down : function(e, m){
36017 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
36018 m.tryActivate(0, 1);
36022 right : function(e, m){
36024 m.activeItem.expandMenu(true);
36028 left : function(e, m){
36030 if(m.parentMenu && m.parentMenu.activeItem){
36031 m.parentMenu.activeItem.activate();
36035 enter : function(e, m){
36037 e.stopPropagation();
36038 m.activeItem.onClick(e);
36039 m.fireEvent("click", this, m.activeItem);
36045 * Ext JS Library 1.1.1
36046 * Copyright(c) 2006-2007, Ext JS, LLC.
36048 * Originally Released Under LGPL - original licence link has changed is not relivant.
36051 * <script type="text/javascript">
36055 * @class Roo.menu.MenuMgr
36056 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
36059 Roo.menu.MenuMgr = function(){
36060 var menus, active, groups = {}, attached = false, lastShow = new Date();
36062 // private - called when first menu is created
36065 active = new Roo.util.MixedCollection();
36066 Roo.get(document).addKeyListener(27, function(){
36067 if(active.length > 0){
36074 function hideAll(){
36075 if(active && active.length > 0){
36076 var c = active.clone();
36077 c.each(function(m){
36084 function onHide(m){
36086 if(active.length < 1){
36087 Roo.get(document).un("mousedown", onMouseDown);
36093 function onShow(m){
36094 var last = active.last();
36095 lastShow = new Date();
36098 Roo.get(document).on("mousedown", onMouseDown);
36102 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36103 m.parentMenu.activeChild = m;
36104 }else if(last && last.isVisible()){
36105 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36110 function onBeforeHide(m){
36112 m.activeChild.hide();
36114 if(m.autoHideTimer){
36115 clearTimeout(m.autoHideTimer);
36116 delete m.autoHideTimer;
36121 function onBeforeShow(m){
36122 var pm = m.parentMenu;
36123 if(!pm && !m.allowOtherMenus){
36125 }else if(pm && pm.activeChild && active != m){
36126 pm.activeChild.hide();
36131 function onMouseDown(e){
36132 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36138 function onBeforeCheck(mi, state){
36140 var g = groups[mi.group];
36141 for(var i = 0, l = g.length; i < l; i++){
36143 g[i].setChecked(false);
36152 * Hides all menus that are currently visible
36154 hideAll : function(){
36159 register : function(menu){
36163 menus[menu.id] = menu;
36164 menu.on("beforehide", onBeforeHide);
36165 menu.on("hide", onHide);
36166 menu.on("beforeshow", onBeforeShow);
36167 menu.on("show", onShow);
36168 var g = menu.group;
36169 if(g && menu.events["checkchange"]){
36173 groups[g].push(menu);
36174 menu.on("checkchange", onCheck);
36179 * Returns a {@link Roo.menu.Menu} object
36180 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36181 * be used to generate and return a new Menu instance.
36183 get : function(menu){
36184 if(typeof menu == "string"){ // menu id
36185 return menus[menu];
36186 }else if(menu.events){ // menu instance
36188 }else if(typeof menu.length == 'number'){ // array of menu items?
36189 return new Roo.menu.Menu({items:menu});
36190 }else{ // otherwise, must be a config
36191 return new Roo.menu.Menu(menu);
36196 unregister : function(menu){
36197 delete menus[menu.id];
36198 menu.un("beforehide", onBeforeHide);
36199 menu.un("hide", onHide);
36200 menu.un("beforeshow", onBeforeShow);
36201 menu.un("show", onShow);
36202 var g = menu.group;
36203 if(g && menu.events["checkchange"]){
36204 groups[g].remove(menu);
36205 menu.un("checkchange", onCheck);
36210 registerCheckable : function(menuItem){
36211 var g = menuItem.group;
36216 groups[g].push(menuItem);
36217 menuItem.on("beforecheckchange", onBeforeCheck);
36222 unregisterCheckable : function(menuItem){
36223 var g = menuItem.group;
36225 groups[g].remove(menuItem);
36226 menuItem.un("beforecheckchange", onBeforeCheck);
36232 * Ext JS Library 1.1.1
36233 * Copyright(c) 2006-2007, Ext JS, LLC.
36235 * Originally Released Under LGPL - original licence link has changed is not relivant.
36238 * <script type="text/javascript">
36243 * @class Roo.menu.BaseItem
36244 * @extends Roo.Component
36245 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36246 * management and base configuration options shared by all menu components.
36248 * Creates a new BaseItem
36249 * @param {Object} config Configuration options
36251 Roo.menu.BaseItem = function(config){
36252 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36257 * Fires when this item is clicked
36258 * @param {Roo.menu.BaseItem} this
36259 * @param {Roo.EventObject} e
36264 * Fires when this item is activated
36265 * @param {Roo.menu.BaseItem} this
36269 * @event deactivate
36270 * Fires when this item is deactivated
36271 * @param {Roo.menu.BaseItem} this
36277 this.on("click", this.handler, this.scope, true);
36281 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36283 * @cfg {Function} handler
36284 * A function that will handle the click event of this menu item (defaults to undefined)
36287 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36289 canActivate : false,
36292 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36297 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36299 activeClass : "x-menu-item-active",
36301 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36303 hideOnClick : true,
36305 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36310 ctype: "Roo.menu.BaseItem",
36313 actionMode : "container",
36316 render : function(container, parentMenu){
36317 this.parentMenu = parentMenu;
36318 Roo.menu.BaseItem.superclass.render.call(this, container);
36319 this.container.menuItemId = this.id;
36323 onRender : function(container, position){
36324 this.el = Roo.get(this.el);
36325 container.dom.appendChild(this.el.dom);
36329 onClick : function(e){
36330 if(!this.disabled && this.fireEvent("click", this, e) !== false
36331 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36332 this.handleClick(e);
36339 activate : function(){
36343 var li = this.container;
36344 li.addClass(this.activeClass);
36345 this.region = li.getRegion().adjust(2, 2, -2, -2);
36346 this.fireEvent("activate", this);
36351 deactivate : function(){
36352 this.container.removeClass(this.activeClass);
36353 this.fireEvent("deactivate", this);
36357 shouldDeactivate : function(e){
36358 return !this.region || !this.region.contains(e.getPoint());
36362 handleClick : function(e){
36363 if(this.hideOnClick){
36364 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36369 expandMenu : function(autoActivate){
36374 hideMenu : function(){
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.Adapter
36390 * @extends Roo.menu.BaseItem
36391 * 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.
36392 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36394 * Creates a new Adapter
36395 * @param {Object} config Configuration options
36397 Roo.menu.Adapter = function(component, config){
36398 Roo.menu.Adapter.superclass.constructor.call(this, config);
36399 this.component = component;
36401 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36403 canActivate : true,
36406 onRender : function(container, position){
36407 this.component.render(container);
36408 this.el = this.component.getEl();
36412 activate : function(){
36416 this.component.focus();
36417 this.fireEvent("activate", this);
36422 deactivate : function(){
36423 this.fireEvent("deactivate", this);
36427 disable : function(){
36428 this.component.disable();
36429 Roo.menu.Adapter.superclass.disable.call(this);
36433 enable : function(){
36434 this.component.enable();
36435 Roo.menu.Adapter.superclass.enable.call(this);
36439 * Ext JS Library 1.1.1
36440 * Copyright(c) 2006-2007, Ext JS, LLC.
36442 * Originally Released Under LGPL - original licence link has changed is not relivant.
36445 * <script type="text/javascript">
36449 * @class Roo.menu.TextItem
36450 * @extends Roo.menu.BaseItem
36451 * Adds a static text string to a menu, usually used as either a heading or group separator.
36452 * Note: old style constructor with text is still supported.
36455 * Creates a new TextItem
36456 * @param {Object} cfg Configuration
36458 Roo.menu.TextItem = function(cfg){
36459 if (typeof(cfg) == 'string') {
36462 Roo.apply(this,cfg);
36465 Roo.menu.TextItem.superclass.constructor.call(this);
36468 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36470 * @cfg {Boolean} text Text to show on item.
36475 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36477 hideOnClick : false,
36479 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36481 itemCls : "x-menu-text",
36484 onRender : function(){
36485 var s = document.createElement("span");
36486 s.className = this.itemCls;
36487 s.innerHTML = this.text;
36489 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36493 * Ext JS Library 1.1.1
36494 * Copyright(c) 2006-2007, Ext JS, LLC.
36496 * Originally Released Under LGPL - original licence link has changed is not relivant.
36499 * <script type="text/javascript">
36503 * @class Roo.menu.Separator
36504 * @extends Roo.menu.BaseItem
36505 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36506 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36508 * @param {Object} config Configuration options
36510 Roo.menu.Separator = function(config){
36511 Roo.menu.Separator.superclass.constructor.call(this, config);
36514 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36516 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36518 itemCls : "x-menu-sep",
36520 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36522 hideOnClick : false,
36525 onRender : function(li){
36526 var s = document.createElement("span");
36527 s.className = this.itemCls;
36528 s.innerHTML = " ";
36530 li.addClass("x-menu-sep-li");
36531 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36535 * Ext JS Library 1.1.1
36536 * Copyright(c) 2006-2007, Ext JS, LLC.
36538 * Originally Released Under LGPL - original licence link has changed is not relivant.
36541 * <script type="text/javascript">
36544 * @class Roo.menu.Item
36545 * @extends Roo.menu.BaseItem
36546 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36547 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36548 * activation and click handling.
36550 * Creates a new Item
36551 * @param {Object} config Configuration options
36553 Roo.menu.Item = function(config){
36554 Roo.menu.Item.superclass.constructor.call(this, config);
36556 this.menu = Roo.menu.MenuMgr.get(this.menu);
36559 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36562 * @cfg {String} text
36563 * The text to show on the menu item.
36567 * @cfg {String} HTML to render in menu
36568 * The text to show on the menu item (HTML version).
36572 * @cfg {String} icon
36573 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36577 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36579 itemCls : "x-menu-item",
36581 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36583 canActivate : true,
36585 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36588 // doc'd in BaseItem
36592 ctype: "Roo.menu.Item",
36595 onRender : function(container, position){
36596 var el = document.createElement("a");
36597 el.hideFocus = true;
36598 el.unselectable = "on";
36599 el.href = this.href || "#";
36600 if(this.hrefTarget){
36601 el.target = this.hrefTarget;
36603 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36605 var html = this.html.length ? this.html : String.format('{0}',this.text);
36607 el.innerHTML = String.format(
36608 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36609 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36611 Roo.menu.Item.superclass.onRender.call(this, container, position);
36615 * Sets the text to display in this menu item
36616 * @param {String} text The text to display
36617 * @param {Boolean} isHTML true to indicate text is pure html.
36619 setText : function(text, isHTML){
36627 var html = this.html.length ? this.html : String.format('{0}',this.text);
36629 this.el.update(String.format(
36630 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36631 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36632 this.parentMenu.autoWidth();
36637 handleClick : function(e){
36638 if(!this.href){ // if no link defined, stop the event automatically
36641 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36645 activate : function(autoExpand){
36646 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36656 shouldDeactivate : function(e){
36657 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36658 if(this.menu && this.menu.isVisible()){
36659 return !this.menu.getEl().getRegion().contains(e.getPoint());
36667 deactivate : function(){
36668 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36673 expandMenu : function(autoActivate){
36674 if(!this.disabled && this.menu){
36675 clearTimeout(this.hideTimer);
36676 delete this.hideTimer;
36677 if(!this.menu.isVisible() && !this.showTimer){
36678 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36679 }else if (this.menu.isVisible() && autoActivate){
36680 this.menu.tryActivate(0, 1);
36686 deferExpand : function(autoActivate){
36687 delete this.showTimer;
36688 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36690 this.menu.tryActivate(0, 1);
36695 hideMenu : function(){
36696 clearTimeout(this.showTimer);
36697 delete this.showTimer;
36698 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36699 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36704 deferHide : function(){
36705 delete this.hideTimer;
36710 * Ext JS Library 1.1.1
36711 * Copyright(c) 2006-2007, Ext JS, LLC.
36713 * Originally Released Under LGPL - original licence link has changed is not relivant.
36716 * <script type="text/javascript">
36720 * @class Roo.menu.CheckItem
36721 * @extends Roo.menu.Item
36722 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36724 * Creates a new CheckItem
36725 * @param {Object} config Configuration options
36727 Roo.menu.CheckItem = function(config){
36728 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36731 * @event beforecheckchange
36732 * Fires before the checked value is set, providing an opportunity to cancel if needed
36733 * @param {Roo.menu.CheckItem} this
36734 * @param {Boolean} checked The new checked value that will be set
36736 "beforecheckchange" : true,
36738 * @event checkchange
36739 * Fires after the checked value has been set
36740 * @param {Roo.menu.CheckItem} this
36741 * @param {Boolean} checked The checked value that was set
36743 "checkchange" : true
36745 if(this.checkHandler){
36746 this.on('checkchange', this.checkHandler, this.scope);
36749 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36751 * @cfg {String} group
36752 * All check items with the same group name will automatically be grouped into a single-select
36753 * radio button group (defaults to '')
36756 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36758 itemCls : "x-menu-item x-menu-check-item",
36760 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36762 groupClass : "x-menu-group-item",
36765 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36766 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36767 * initialized with checked = true will be rendered as checked.
36772 ctype: "Roo.menu.CheckItem",
36775 onRender : function(c){
36776 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36778 this.el.addClass(this.groupClass);
36780 Roo.menu.MenuMgr.registerCheckable(this);
36782 this.checked = false;
36783 this.setChecked(true, true);
36788 destroy : function(){
36790 Roo.menu.MenuMgr.unregisterCheckable(this);
36792 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36796 * Set the checked state of this item
36797 * @param {Boolean} checked The new checked value
36798 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36800 setChecked : function(state, suppressEvent){
36801 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36802 if(this.container){
36803 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36805 this.checked = state;
36806 if(suppressEvent !== true){
36807 this.fireEvent("checkchange", this, state);
36813 handleClick : function(e){
36814 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36815 this.setChecked(!this.checked);
36817 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36821 * Ext JS Library 1.1.1
36822 * Copyright(c) 2006-2007, Ext JS, LLC.
36824 * Originally Released Under LGPL - original licence link has changed is not relivant.
36827 * <script type="text/javascript">
36831 * @class Roo.menu.DateItem
36832 * @extends Roo.menu.Adapter
36833 * A menu item that wraps the {@link Roo.DatPicker} component.
36835 * Creates a new DateItem
36836 * @param {Object} config Configuration options
36838 Roo.menu.DateItem = function(config){
36839 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36840 /** The Roo.DatePicker object @type Roo.DatePicker */
36841 this.picker = this.component;
36842 this.addEvents({select: true});
36844 this.picker.on("render", function(picker){
36845 picker.getEl().swallowEvent("click");
36846 picker.container.addClass("x-menu-date-item");
36849 this.picker.on("select", this.onSelect, this);
36852 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36854 onSelect : function(picker, date){
36855 this.fireEvent("select", this, date, picker);
36856 Roo.menu.DateItem.superclass.handleClick.call(this);
36860 * Ext JS Library 1.1.1
36861 * Copyright(c) 2006-2007, Ext JS, LLC.
36863 * Originally Released Under LGPL - original licence link has changed is not relivant.
36866 * <script type="text/javascript">
36870 * @class Roo.menu.ColorItem
36871 * @extends Roo.menu.Adapter
36872 * A menu item that wraps the {@link Roo.ColorPalette} component.
36874 * Creates a new ColorItem
36875 * @param {Object} config Configuration options
36877 Roo.menu.ColorItem = function(config){
36878 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36879 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36880 this.palette = this.component;
36881 this.relayEvents(this.palette, ["select"]);
36882 if(this.selectHandler){
36883 this.on('select', this.selectHandler, this.scope);
36886 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36888 * Ext JS Library 1.1.1
36889 * Copyright(c) 2006-2007, Ext JS, LLC.
36891 * Originally Released Under LGPL - original licence link has changed is not relivant.
36894 * <script type="text/javascript">
36899 * @class Roo.menu.DateMenu
36900 * @extends Roo.menu.Menu
36901 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36903 * Creates a new DateMenu
36904 * @param {Object} config Configuration options
36906 Roo.menu.DateMenu = function(config){
36907 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36909 var di = new Roo.menu.DateItem(config);
36912 * The {@link Roo.DatePicker} instance for this DateMenu
36915 this.picker = di.picker;
36918 * @param {DatePicker} picker
36919 * @param {Date} date
36921 this.relayEvents(di, ["select"]);
36922 this.on('beforeshow', function(){
36924 this.picker.hideMonthPicker(false);
36928 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36932 * Ext JS Library 1.1.1
36933 * Copyright(c) 2006-2007, Ext JS, LLC.
36935 * Originally Released Under LGPL - original licence link has changed is not relivant.
36938 * <script type="text/javascript">
36943 * @class Roo.menu.ColorMenu
36944 * @extends Roo.menu.Menu
36945 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36947 * Creates a new ColorMenu
36948 * @param {Object} config Configuration options
36950 Roo.menu.ColorMenu = function(config){
36951 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36953 var ci = new Roo.menu.ColorItem(config);
36956 * The {@link Roo.ColorPalette} instance for this ColorMenu
36957 * @type ColorPalette
36959 this.palette = ci.palette;
36962 * @param {ColorPalette} palette
36963 * @param {String} color
36965 this.relayEvents(ci, ["select"]);
36967 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36969 * Ext JS Library 1.1.1
36970 * Copyright(c) 2006-2007, Ext JS, LLC.
36972 * Originally Released Under LGPL - original licence link has changed is not relivant.
36975 * <script type="text/javascript">
36979 * @class Roo.form.Field
36980 * @extends Roo.BoxComponent
36981 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36983 * Creates a new Field
36984 * @param {Object} config Configuration options
36986 Roo.form.Field = function(config){
36987 Roo.form.Field.superclass.constructor.call(this, config);
36990 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36992 * @cfg {String} fieldLabel Label to use when rendering a form.
36995 * @cfg {String} qtip Mouse over tip
36999 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
37001 invalidClass : "x-form-invalid",
37003 * @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")
37005 invalidText : "The value in this field is invalid",
37007 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
37009 focusClass : "x-form-focus",
37011 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
37012 automatic validation (defaults to "keyup").
37014 validationEvent : "keyup",
37016 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
37018 validateOnBlur : true,
37020 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
37022 validationDelay : 250,
37024 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37025 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
37027 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
37029 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
37031 fieldClass : "x-form-field",
37033 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
37036 ----------- ----------------------------------------------------------------------
37037 qtip Display a quick tip when the user hovers over the field
37038 title Display a default browser title attribute popup
37039 under Add a block div beneath the field containing the error text
37040 side Add an error icon to the right of the field with a popup on hover
37041 [element id] Add the error text directly to the innerHTML of the specified element
37044 msgTarget : 'qtip',
37046 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
37051 * @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.
37056 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37061 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37063 inputType : undefined,
37066 * @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).
37068 tabIndex : undefined,
37071 isFormField : true,
37076 * @property {Roo.Element} fieldEl
37077 * Element Containing the rendered Field (with label etc.)
37080 * @cfg {Mixed} value A value to initialize this field with.
37085 * @cfg {String} name The field's HTML name attribute.
37088 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37092 initComponent : function(){
37093 Roo.form.Field.superclass.initComponent.call(this);
37097 * Fires when this field receives input focus.
37098 * @param {Roo.form.Field} this
37103 * Fires when this field loses input focus.
37104 * @param {Roo.form.Field} this
37108 * @event specialkey
37109 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37110 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37111 * @param {Roo.form.Field} this
37112 * @param {Roo.EventObject} e The event object
37117 * Fires just before the field blurs if the field value has changed.
37118 * @param {Roo.form.Field} this
37119 * @param {Mixed} newValue The new value
37120 * @param {Mixed} oldValue The original value
37125 * Fires after the field has been marked as invalid.
37126 * @param {Roo.form.Field} this
37127 * @param {String} msg The validation message
37132 * Fires after the field has been validated with no errors.
37133 * @param {Roo.form.Field} this
37138 * Fires after the key up
37139 * @param {Roo.form.Field} this
37140 * @param {Roo.EventObject} e The event Object
37147 * Returns the name attribute of the field if available
37148 * @return {String} name The field name
37150 getName: function(){
37151 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37155 onRender : function(ct, position){
37156 Roo.form.Field.superclass.onRender.call(this, ct, position);
37158 var cfg = this.getAutoCreate();
37160 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37162 if (!cfg.name.length) {
37165 if(this.inputType){
37166 cfg.type = this.inputType;
37168 this.el = ct.createChild(cfg, position);
37170 var type = this.el.dom.type;
37172 if(type == 'password'){
37175 this.el.addClass('x-form-'+type);
37178 this.el.dom.readOnly = true;
37180 if(this.tabIndex !== undefined){
37181 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37184 this.el.addClass([this.fieldClass, this.cls]);
37189 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37190 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37191 * @return {Roo.form.Field} this
37193 applyTo : function(target){
37194 this.allowDomMove = false;
37195 this.el = Roo.get(target);
37196 this.render(this.el.dom.parentNode);
37201 initValue : function(){
37202 if(this.value !== undefined){
37203 this.setValue(this.value);
37204 }else if(this.el.dom.value.length > 0){
37205 this.setValue(this.el.dom.value);
37210 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37212 isDirty : function() {
37213 if(this.disabled) {
37216 return String(this.getValue()) !== String(this.originalValue);
37220 afterRender : function(){
37221 Roo.form.Field.superclass.afterRender.call(this);
37226 fireKey : function(e){
37227 //Roo.log('field ' + e.getKey());
37228 if(e.isNavKeyPress()){
37229 this.fireEvent("specialkey", this, e);
37234 * Resets the current field value to the originally loaded value and clears any validation messages
37236 reset : function(){
37237 this.setValue(this.resetValue);
37238 this.clearInvalid();
37242 initEvents : function(){
37243 // safari killled keypress - so keydown is now used..
37244 this.el.on("keydown" , this.fireKey, this);
37245 this.el.on("focus", this.onFocus, this);
37246 this.el.on("blur", this.onBlur, this);
37247 this.el.relayEvent('keyup', this);
37249 // reference to original value for reset
37250 this.originalValue = this.getValue();
37251 this.resetValue = this.getValue();
37255 onFocus : function(){
37256 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37257 this.el.addClass(this.focusClass);
37259 if(!this.hasFocus){
37260 this.hasFocus = true;
37261 this.startValue = this.getValue();
37262 this.fireEvent("focus", this);
37266 beforeBlur : Roo.emptyFn,
37269 onBlur : function(){
37271 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37272 this.el.removeClass(this.focusClass);
37274 this.hasFocus = false;
37275 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37278 var v = this.getValue();
37279 if(String(v) !== String(this.startValue)){
37280 this.fireEvent('change', this, v, this.startValue);
37282 this.fireEvent("blur", this);
37286 * Returns whether or not the field value is currently valid
37287 * @param {Boolean} preventMark True to disable marking the field invalid
37288 * @return {Boolean} True if the value is valid, else false
37290 isValid : function(preventMark){
37294 var restore = this.preventMark;
37295 this.preventMark = preventMark === true;
37296 var v = this.validateValue(this.processValue(this.getRawValue()));
37297 this.preventMark = restore;
37302 * Validates the field value
37303 * @return {Boolean} True if the value is valid, else false
37305 validate : function(){
37306 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37307 this.clearInvalid();
37313 processValue : function(value){
37318 // Subclasses should provide the validation implementation by overriding this
37319 validateValue : function(value){
37324 * Mark this field as invalid
37325 * @param {String} msg The validation message
37327 markInvalid : function(msg){
37328 if(!this.rendered || this.preventMark){ // not rendered
37332 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37334 obj.el.addClass(this.invalidClass);
37335 msg = msg || this.invalidText;
37336 switch(this.msgTarget){
37338 obj.el.dom.qtip = msg;
37339 obj.el.dom.qclass = 'x-form-invalid-tip';
37340 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37341 Roo.QuickTips.enable();
37345 this.el.dom.title = msg;
37349 var elp = this.el.findParent('.x-form-element', 5, true);
37350 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37351 this.errorEl.setWidth(elp.getWidth(true)-20);
37353 this.errorEl.update(msg);
37354 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37357 if(!this.errorIcon){
37358 var elp = this.el.findParent('.x-form-element', 5, true);
37359 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37361 this.alignErrorIcon();
37362 this.errorIcon.dom.qtip = msg;
37363 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37364 this.errorIcon.show();
37365 this.on('resize', this.alignErrorIcon, this);
37368 var t = Roo.getDom(this.msgTarget);
37370 t.style.display = this.msgDisplay;
37373 this.fireEvent('invalid', this, msg);
37377 alignErrorIcon : function(){
37378 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37382 * Clear any invalid styles/messages for this field
37384 clearInvalid : function(){
37385 if(!this.rendered || this.preventMark){ // not rendered
37388 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37390 obj.el.removeClass(this.invalidClass);
37391 switch(this.msgTarget){
37393 obj.el.dom.qtip = '';
37396 this.el.dom.title = '';
37400 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37404 if(this.errorIcon){
37405 this.errorIcon.dom.qtip = '';
37406 this.errorIcon.hide();
37407 this.un('resize', this.alignErrorIcon, this);
37411 var t = Roo.getDom(this.msgTarget);
37413 t.style.display = 'none';
37416 this.fireEvent('valid', this);
37420 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37421 * @return {Mixed} value The field value
37423 getRawValue : function(){
37424 var v = this.el.getValue();
37430 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37431 * @return {Mixed} value The field value
37433 getValue : function(){
37434 var v = this.el.getValue();
37440 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37441 * @param {Mixed} value The value to set
37443 setRawValue : function(v){
37444 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37448 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37449 * @param {Mixed} value The value to set
37451 setValue : function(v){
37454 this.el.dom.value = (v === null || v === undefined ? '' : v);
37459 adjustSize : function(w, h){
37460 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37461 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37465 adjustWidth : function(tag, w){
37466 tag = tag.toLowerCase();
37467 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37468 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37469 if(tag == 'input'){
37472 if(tag == 'textarea'){
37475 }else if(Roo.isOpera){
37476 if(tag == 'input'){
37479 if(tag == 'textarea'){
37489 // anything other than normal should be considered experimental
37490 Roo.form.Field.msgFx = {
37492 show: function(msgEl, f){
37493 msgEl.setDisplayed('block');
37496 hide : function(msgEl, f){
37497 msgEl.setDisplayed(false).update('');
37502 show: function(msgEl, f){
37503 msgEl.slideIn('t', {stopFx:true});
37506 hide : function(msgEl, f){
37507 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37512 show: function(msgEl, f){
37513 msgEl.fixDisplay();
37514 msgEl.alignTo(f.el, 'tl-tr');
37515 msgEl.slideIn('l', {stopFx:true});
37518 hide : function(msgEl, f){
37519 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37524 * Ext JS Library 1.1.1
37525 * Copyright(c) 2006-2007, Ext JS, LLC.
37527 * Originally Released Under LGPL - original licence link has changed is not relivant.
37530 * <script type="text/javascript">
37535 * @class Roo.form.TextField
37536 * @extends Roo.form.Field
37537 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37538 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37540 * Creates a new TextField
37541 * @param {Object} config Configuration options
37543 Roo.form.TextField = function(config){
37544 Roo.form.TextField.superclass.constructor.call(this, config);
37548 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37549 * according to the default logic, but this event provides a hook for the developer to apply additional
37550 * logic at runtime to resize the field if needed.
37551 * @param {Roo.form.Field} this This text field
37552 * @param {Number} width The new field width
37558 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37560 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37564 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37568 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37572 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37576 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37580 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37582 disableKeyFilter : false,
37584 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37588 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37592 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37594 maxLength : Number.MAX_VALUE,
37596 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37598 minLengthText : "The minimum length for this field is {0}",
37600 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37602 maxLengthText : "The maximum length for this field is {0}",
37604 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37606 selectOnFocus : false,
37608 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37610 blankText : "This field is required",
37612 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37613 * If available, this function will be called only after the basic validators all return true, and will be passed the
37614 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37618 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37619 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37620 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37624 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37628 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37634 initEvents : function()
37636 if (this.emptyText) {
37637 this.el.attr('placeholder', this.emptyText);
37640 Roo.form.TextField.superclass.initEvents.call(this);
37641 if(this.validationEvent == 'keyup'){
37642 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37643 this.el.on('keyup', this.filterValidation, this);
37645 else if(this.validationEvent !== false){
37646 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37649 if(this.selectOnFocus){
37650 this.on("focus", this.preFocus, this);
37653 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37654 this.el.on("keypress", this.filterKeys, this);
37657 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37658 this.el.on("click", this.autoSize, this);
37660 if(this.el.is('input[type=password]') && Roo.isSafari){
37661 this.el.on('keydown', this.SafariOnKeyDown, this);
37665 processValue : function(value){
37666 if(this.stripCharsRe){
37667 var newValue = value.replace(this.stripCharsRe, '');
37668 if(newValue !== value){
37669 this.setRawValue(newValue);
37676 filterValidation : function(e){
37677 if(!e.isNavKeyPress()){
37678 this.validationTask.delay(this.validationDelay);
37683 onKeyUp : function(e){
37684 if(!e.isNavKeyPress()){
37690 * Resets the current field value to the originally-loaded value and clears any validation messages.
37693 reset : function(){
37694 Roo.form.TextField.superclass.reset.call(this);
37700 preFocus : function(){
37702 if(this.selectOnFocus){
37703 this.el.dom.select();
37709 filterKeys : function(e){
37710 var k = e.getKey();
37711 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37714 var c = e.getCharCode(), cc = String.fromCharCode(c);
37715 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37718 if(!this.maskRe.test(cc)){
37723 setValue : function(v){
37725 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37731 * Validates a value according to the field's validation rules and marks the field as invalid
37732 * if the validation fails
37733 * @param {Mixed} value The value to validate
37734 * @return {Boolean} True if the value is valid, else false
37736 validateValue : function(value){
37737 if(value.length < 1) { // if it's blank
37738 if(this.allowBlank){
37739 this.clearInvalid();
37742 this.markInvalid(this.blankText);
37746 if(value.length < this.minLength){
37747 this.markInvalid(String.format(this.minLengthText, this.minLength));
37750 if(value.length > this.maxLength){
37751 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37755 var vt = Roo.form.VTypes;
37756 if(!vt[this.vtype](value, this)){
37757 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37761 if(typeof this.validator == "function"){
37762 var msg = this.validator(value);
37764 this.markInvalid(msg);
37768 if(this.regex && !this.regex.test(value)){
37769 this.markInvalid(this.regexText);
37776 * Selects text in this field
37777 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37778 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37780 selectText : function(start, end){
37781 var v = this.getRawValue();
37783 start = start === undefined ? 0 : start;
37784 end = end === undefined ? v.length : end;
37785 var d = this.el.dom;
37786 if(d.setSelectionRange){
37787 d.setSelectionRange(start, end);
37788 }else if(d.createTextRange){
37789 var range = d.createTextRange();
37790 range.moveStart("character", start);
37791 range.moveEnd("character", v.length-end);
37798 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37799 * This only takes effect if grow = true, and fires the autosize event.
37801 autoSize : function(){
37802 if(!this.grow || !this.rendered){
37806 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37809 var v = el.dom.value;
37810 var d = document.createElement('div');
37811 d.appendChild(document.createTextNode(v));
37815 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37816 this.el.setWidth(w);
37817 this.fireEvent("autosize", this, w);
37821 SafariOnKeyDown : function(event)
37823 // this is a workaround for a password hang bug on chrome/ webkit.
37825 var isSelectAll = false;
37827 if(this.el.dom.selectionEnd > 0){
37828 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37830 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37831 event.preventDefault();
37836 if(isSelectAll){ // backspace and delete key
37838 event.preventDefault();
37839 // this is very hacky as keydown always get's upper case.
37841 var cc = String.fromCharCode(event.getCharCode());
37842 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37850 * Ext JS Library 1.1.1
37851 * Copyright(c) 2006-2007, Ext JS, LLC.
37853 * Originally Released Under LGPL - original licence link has changed is not relivant.
37856 * <script type="text/javascript">
37860 * @class Roo.form.Hidden
37861 * @extends Roo.form.TextField
37862 * Simple Hidden element used on forms
37864 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37867 * Creates a new Hidden form element.
37868 * @param {Object} config Configuration options
37873 // easy hidden field...
37874 Roo.form.Hidden = function(config){
37875 Roo.form.Hidden.superclass.constructor.call(this, config);
37878 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37880 inputType: 'hidden',
37883 labelSeparator: '',
37885 itemCls : 'x-form-item-display-none'
37893 * Ext JS Library 1.1.1
37894 * Copyright(c) 2006-2007, Ext JS, LLC.
37896 * Originally Released Under LGPL - original licence link has changed is not relivant.
37899 * <script type="text/javascript">
37903 * @class Roo.form.TriggerField
37904 * @extends Roo.form.TextField
37905 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37906 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37907 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37908 * for which you can provide a custom implementation. For example:
37910 var trigger = new Roo.form.TriggerField();
37911 trigger.onTriggerClick = myTriggerFn;
37912 trigger.applyTo('my-field');
37915 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37916 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37917 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37918 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37920 * Create a new TriggerField.
37921 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37922 * to the base TextField)
37924 Roo.form.TriggerField = function(config){
37925 this.mimicing = false;
37926 Roo.form.TriggerField.superclass.constructor.call(this, config);
37929 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37931 * @cfg {String} triggerClass A CSS class to apply to the trigger
37934 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37935 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37937 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37939 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37943 /** @cfg {Boolean} grow @hide */
37944 /** @cfg {Number} growMin @hide */
37945 /** @cfg {Number} growMax @hide */
37951 autoSize: Roo.emptyFn,
37955 deferHeight : true,
37958 actionMode : 'wrap',
37960 onResize : function(w, h){
37961 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37962 if(typeof w == 'number'){
37963 var x = w - this.trigger.getWidth();
37964 this.el.setWidth(this.adjustWidth('input', x));
37965 this.trigger.setStyle('left', x+'px');
37970 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37973 getResizeEl : function(){
37978 getPositionEl : function(){
37983 alignErrorIcon : function(){
37984 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37988 onRender : function(ct, position){
37989 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37990 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37991 this.trigger = this.wrap.createChild(this.triggerConfig ||
37992 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37993 if(this.hideTrigger){
37994 this.trigger.setDisplayed(false);
37996 this.initTrigger();
37998 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
38003 initTrigger : function(){
38004 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
38005 this.trigger.addClassOnOver('x-form-trigger-over');
38006 this.trigger.addClassOnClick('x-form-trigger-click');
38010 onDestroy : function(){
38012 this.trigger.removeAllListeners();
38013 this.trigger.remove();
38016 this.wrap.remove();
38018 Roo.form.TriggerField.superclass.onDestroy.call(this);
38022 onFocus : function(){
38023 Roo.form.TriggerField.superclass.onFocus.call(this);
38024 if(!this.mimicing){
38025 this.wrap.addClass('x-trigger-wrap-focus');
38026 this.mimicing = true;
38027 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
38028 if(this.monitorTab){
38029 this.el.on("keydown", this.checkTab, this);
38035 checkTab : function(e){
38036 if(e.getKey() == e.TAB){
38037 this.triggerBlur();
38042 onBlur : function(){
38047 mimicBlur : function(e, t){
38048 if(!this.wrap.contains(t) && this.validateBlur()){
38049 this.triggerBlur();
38054 triggerBlur : function(){
38055 this.mimicing = false;
38056 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
38057 if(this.monitorTab){
38058 this.el.un("keydown", this.checkTab, this);
38060 this.wrap.removeClass('x-trigger-wrap-focus');
38061 Roo.form.TriggerField.superclass.onBlur.call(this);
38065 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38066 validateBlur : function(e, t){
38071 onDisable : function(){
38072 Roo.form.TriggerField.superclass.onDisable.call(this);
38074 this.wrap.addClass('x-item-disabled');
38079 onEnable : function(){
38080 Roo.form.TriggerField.superclass.onEnable.call(this);
38082 this.wrap.removeClass('x-item-disabled');
38087 onShow : function(){
38088 var ae = this.getActionEl();
38091 ae.dom.style.display = '';
38092 ae.dom.style.visibility = 'visible';
38098 onHide : function(){
38099 var ae = this.getActionEl();
38100 ae.dom.style.display = 'none';
38104 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38105 * by an implementing function.
38107 * @param {EventObject} e
38109 onTriggerClick : Roo.emptyFn
38112 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38113 // to be extended by an implementing class. For an example of implementing this class, see the custom
38114 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38115 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38116 initComponent : function(){
38117 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38119 this.triggerConfig = {
38120 tag:'span', cls:'x-form-twin-triggers', cn:[
38121 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38122 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38126 getTrigger : function(index){
38127 return this.triggers[index];
38130 initTrigger : function(){
38131 var ts = this.trigger.select('.x-form-trigger', true);
38132 this.wrap.setStyle('overflow', 'hidden');
38133 var triggerField = this;
38134 ts.each(function(t, all, index){
38135 t.hide = function(){
38136 var w = triggerField.wrap.getWidth();
38137 this.dom.style.display = 'none';
38138 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38140 t.show = function(){
38141 var w = triggerField.wrap.getWidth();
38142 this.dom.style.display = '';
38143 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38145 var triggerIndex = 'Trigger'+(index+1);
38147 if(this['hide'+triggerIndex]){
38148 t.dom.style.display = 'none';
38150 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38151 t.addClassOnOver('x-form-trigger-over');
38152 t.addClassOnClick('x-form-trigger-click');
38154 this.triggers = ts.elements;
38157 onTrigger1Click : Roo.emptyFn,
38158 onTrigger2Click : Roo.emptyFn
38161 * Ext JS Library 1.1.1
38162 * Copyright(c) 2006-2007, Ext JS, LLC.
38164 * Originally Released Under LGPL - original licence link has changed is not relivant.
38167 * <script type="text/javascript">
38171 * @class Roo.form.TextArea
38172 * @extends Roo.form.TextField
38173 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38174 * support for auto-sizing.
38176 * Creates a new TextArea
38177 * @param {Object} config Configuration options
38179 Roo.form.TextArea = function(config){
38180 Roo.form.TextArea.superclass.constructor.call(this, config);
38181 // these are provided exchanges for backwards compat
38182 // minHeight/maxHeight were replaced by growMin/growMax to be
38183 // compatible with TextField growing config values
38184 if(this.minHeight !== undefined){
38185 this.growMin = this.minHeight;
38187 if(this.maxHeight !== undefined){
38188 this.growMax = this.maxHeight;
38192 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38194 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38198 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38202 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38203 * in the field (equivalent to setting overflow: hidden, defaults to false)
38205 preventScrollbars: false,
38207 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38208 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38212 onRender : function(ct, position){
38214 this.defaultAutoCreate = {
38216 style:"width:300px;height:60px;",
38217 autocomplete: "off"
38220 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38222 this.textSizeEl = Roo.DomHelper.append(document.body, {
38223 tag: "pre", cls: "x-form-grow-sizer"
38225 if(this.preventScrollbars){
38226 this.el.setStyle("overflow", "hidden");
38228 this.el.setHeight(this.growMin);
38232 onDestroy : function(){
38233 if(this.textSizeEl){
38234 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38236 Roo.form.TextArea.superclass.onDestroy.call(this);
38240 onKeyUp : function(e){
38241 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38247 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38248 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38250 autoSize : function(){
38251 if(!this.grow || !this.textSizeEl){
38255 var v = el.dom.value;
38256 var ts = this.textSizeEl;
38259 ts.appendChild(document.createTextNode(v));
38262 Roo.fly(ts).setWidth(this.el.getWidth());
38264 v = "  ";
38267 v = v.replace(/\n/g, '<p> </p>');
38269 v += " \n ";
38272 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38273 if(h != this.lastHeight){
38274 this.lastHeight = h;
38275 this.el.setHeight(h);
38276 this.fireEvent("autosize", this, h);
38281 * Ext JS Library 1.1.1
38282 * Copyright(c) 2006-2007, Ext JS, LLC.
38284 * Originally Released Under LGPL - original licence link has changed is not relivant.
38287 * <script type="text/javascript">
38292 * @class Roo.form.NumberField
38293 * @extends Roo.form.TextField
38294 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38296 * Creates a new NumberField
38297 * @param {Object} config Configuration options
38299 Roo.form.NumberField = function(config){
38300 Roo.form.NumberField.superclass.constructor.call(this, config);
38303 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38305 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38307 fieldClass: "x-form-field x-form-num-field",
38309 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38311 allowDecimals : true,
38313 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38315 decimalSeparator : ".",
38317 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38319 decimalPrecision : 2,
38321 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38323 allowNegative : true,
38325 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38327 minValue : Number.NEGATIVE_INFINITY,
38329 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38331 maxValue : Number.MAX_VALUE,
38333 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38335 minText : "The minimum value for this field is {0}",
38337 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38339 maxText : "The maximum value for this field is {0}",
38341 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38342 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38344 nanText : "{0} is not a valid number",
38347 initEvents : function(){
38348 Roo.form.NumberField.superclass.initEvents.call(this);
38349 var allowed = "0123456789";
38350 if(this.allowDecimals){
38351 allowed += this.decimalSeparator;
38353 if(this.allowNegative){
38356 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38357 var keyPress = function(e){
38358 var k = e.getKey();
38359 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38362 var c = e.getCharCode();
38363 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38367 this.el.on("keypress", keyPress, this);
38371 validateValue : function(value){
38372 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38375 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38378 var num = this.parseValue(value);
38380 this.markInvalid(String.format(this.nanText, value));
38383 if(num < this.minValue){
38384 this.markInvalid(String.format(this.minText, this.minValue));
38387 if(num > this.maxValue){
38388 this.markInvalid(String.format(this.maxText, this.maxValue));
38394 getValue : function(){
38395 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38399 parseValue : function(value){
38400 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38401 return isNaN(value) ? '' : value;
38405 fixPrecision : function(value){
38406 var nan = isNaN(value);
38407 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38408 return nan ? '' : value;
38410 return parseFloat(value).toFixed(this.decimalPrecision);
38413 setValue : function(v){
38414 v = this.fixPrecision(v);
38415 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38419 decimalPrecisionFcn : function(v){
38420 return Math.floor(v);
38423 beforeBlur : function(){
38424 var v = this.parseValue(this.getRawValue());
38431 * Ext JS Library 1.1.1
38432 * Copyright(c) 2006-2007, Ext JS, LLC.
38434 * Originally Released Under LGPL - original licence link has changed is not relivant.
38437 * <script type="text/javascript">
38441 * @class Roo.form.DateField
38442 * @extends Roo.form.TriggerField
38443 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38445 * Create a new DateField
38446 * @param {Object} config
38448 Roo.form.DateField = function(config){
38449 Roo.form.DateField.superclass.constructor.call(this, config);
38455 * Fires when a date is selected
38456 * @param {Roo.form.DateField} combo This combo box
38457 * @param {Date} date The date selected
38464 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38465 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38466 this.ddMatch = null;
38467 if(this.disabledDates){
38468 var dd = this.disabledDates;
38470 for(var i = 0; i < dd.length; i++){
38472 if(i != dd.length-1) re += "|";
38474 this.ddMatch = new RegExp(re + ")");
38478 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38480 * @cfg {String} format
38481 * The default date format string which can be overriden for localization support. The format must be
38482 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38486 * @cfg {String} altFormats
38487 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38488 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38490 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38492 * @cfg {Array} disabledDays
38493 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38495 disabledDays : null,
38497 * @cfg {String} disabledDaysText
38498 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38500 disabledDaysText : "Disabled",
38502 * @cfg {Array} disabledDates
38503 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38504 * expression so they are very powerful. Some examples:
38506 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38507 * <li>["03/08", "09/16"] would disable those days for every year</li>
38508 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38509 * <li>["03/../2006"] would disable every day in March 2006</li>
38510 * <li>["^03"] would disable every day in every March</li>
38512 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38513 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38515 disabledDates : null,
38517 * @cfg {String} disabledDatesText
38518 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38520 disabledDatesText : "Disabled",
38522 * @cfg {Date/String} minValue
38523 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38524 * valid format (defaults to null).
38528 * @cfg {Date/String} maxValue
38529 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38530 * valid format (defaults to null).
38534 * @cfg {String} minText
38535 * The error text to display when the date in the cell is before minValue (defaults to
38536 * 'The date in this field must be after {minValue}').
38538 minText : "The date in this field must be equal to or after {0}",
38540 * @cfg {String} maxText
38541 * The error text to display when the date in the cell is after maxValue (defaults to
38542 * 'The date in this field must be before {maxValue}').
38544 maxText : "The date in this field must be equal to or before {0}",
38546 * @cfg {String} invalidText
38547 * The error text to display when the date in the field is invalid (defaults to
38548 * '{value} is not a valid date - it must be in the format {format}').
38550 invalidText : "{0} is not a valid date - it must be in the format {1}",
38552 * @cfg {String} triggerClass
38553 * An additional CSS class used to style the trigger button. The trigger will always get the
38554 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38555 * which displays a calendar icon).
38557 triggerClass : 'x-form-date-trigger',
38561 * @cfg {Boolean} useIso
38562 * if enabled, then the date field will use a hidden field to store the
38563 * real value as iso formated date. default (false)
38567 * @cfg {String/Object} autoCreate
38568 * A DomHelper element spec, or true for a default element spec (defaults to
38569 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38572 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38575 hiddenField: false,
38577 onRender : function(ct, position)
38579 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38581 //this.el.dom.removeAttribute('name');
38582 Roo.log("Changing name?");
38583 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38584 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38586 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38587 // prevent input submission
38588 this.hiddenName = this.name;
38595 validateValue : function(value)
38597 value = this.formatDate(value);
38598 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38599 Roo.log('super failed');
38602 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38605 var svalue = value;
38606 value = this.parseDate(value);
38608 Roo.log('parse date failed' + svalue);
38609 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38612 var time = value.getTime();
38613 if(this.minValue && time < this.minValue.getTime()){
38614 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38617 if(this.maxValue && time > this.maxValue.getTime()){
38618 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38621 if(this.disabledDays){
38622 var day = value.getDay();
38623 for(var i = 0; i < this.disabledDays.length; i++) {
38624 if(day === this.disabledDays[i]){
38625 this.markInvalid(this.disabledDaysText);
38630 var fvalue = this.formatDate(value);
38631 if(this.ddMatch && this.ddMatch.test(fvalue)){
38632 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38639 // Provides logic to override the default TriggerField.validateBlur which just returns true
38640 validateBlur : function(){
38641 return !this.menu || !this.menu.isVisible();
38644 getName: function()
38646 // returns hidden if it's set..
38647 if (!this.rendered) {return ''};
38648 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38653 * Returns the current date value of the date field.
38654 * @return {Date} The date value
38656 getValue : function(){
38658 return this.hiddenField ?
38659 this.hiddenField.value :
38660 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38664 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38665 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38666 * (the default format used is "m/d/y").
38669 //All of these calls set the same date value (May 4, 2006)
38671 //Pass a date object:
38672 var dt = new Date('5/4/06');
38673 dateField.setValue(dt);
38675 //Pass a date string (default format):
38676 dateField.setValue('5/4/06');
38678 //Pass a date string (custom format):
38679 dateField.format = 'Y-m-d';
38680 dateField.setValue('2006-5-4');
38682 * @param {String/Date} date The date or valid date string
38684 setValue : function(date){
38685 if (this.hiddenField) {
38686 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38688 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38689 // make sure the value field is always stored as a date..
38690 this.value = this.parseDate(date);
38696 parseDate : function(value){
38697 if(!value || value instanceof Date){
38700 var v = Date.parseDate(value, this.format);
38701 if (!v && this.useIso) {
38702 v = Date.parseDate(value, 'Y-m-d');
38704 if(!v && this.altFormats){
38705 if(!this.altFormatsArray){
38706 this.altFormatsArray = this.altFormats.split("|");
38708 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38709 v = Date.parseDate(value, this.altFormatsArray[i]);
38716 formatDate : function(date, fmt){
38717 return (!date || !(date instanceof Date)) ?
38718 date : date.dateFormat(fmt || this.format);
38723 select: function(m, d){
38726 this.fireEvent('select', this, d);
38728 show : function(){ // retain focus styling
38732 this.focus.defer(10, this);
38733 var ml = this.menuListeners;
38734 this.menu.un("select", ml.select, this);
38735 this.menu.un("show", ml.show, this);
38736 this.menu.un("hide", ml.hide, this);
38741 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38742 onTriggerClick : function(){
38746 if(this.menu == null){
38747 this.menu = new Roo.menu.DateMenu();
38749 Roo.apply(this.menu.picker, {
38750 showClear: this.allowBlank,
38751 minDate : this.minValue,
38752 maxDate : this.maxValue,
38753 disabledDatesRE : this.ddMatch,
38754 disabledDatesText : this.disabledDatesText,
38755 disabledDays : this.disabledDays,
38756 disabledDaysText : this.disabledDaysText,
38757 format : this.useIso ? 'Y-m-d' : this.format,
38758 minText : String.format(this.minText, this.formatDate(this.minValue)),
38759 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38761 this.menu.on(Roo.apply({}, this.menuListeners, {
38764 this.menu.picker.setValue(this.getValue() || new Date());
38765 this.menu.show(this.el, "tl-bl?");
38768 beforeBlur : function(){
38769 var v = this.parseDate(this.getRawValue());
38779 isDirty : function() {
38780 if(this.disabled) {
38784 if(typeof(this.startValue) === 'undefined'){
38788 return String(this.getValue()) !== String(this.startValue);
38793 * Ext JS Library 1.1.1
38794 * Copyright(c) 2006-2007, Ext JS, LLC.
38796 * Originally Released Under LGPL - original licence link has changed is not relivant.
38799 * <script type="text/javascript">
38803 * @class Roo.form.MonthField
38804 * @extends Roo.form.TriggerField
38805 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38807 * Create a new MonthField
38808 * @param {Object} config
38810 Roo.form.MonthField = function(config){
38812 Roo.form.MonthField.superclass.constructor.call(this, config);
38818 * Fires when a date is selected
38819 * @param {Roo.form.MonthFieeld} combo This combo box
38820 * @param {Date} date The date selected
38827 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38828 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38829 this.ddMatch = null;
38830 if(this.disabledDates){
38831 var dd = this.disabledDates;
38833 for(var i = 0; i < dd.length; i++){
38835 if(i != dd.length-1) re += "|";
38837 this.ddMatch = new RegExp(re + ")");
38841 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38843 * @cfg {String} format
38844 * The default date format string which can be overriden for localization support. The format must be
38845 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38849 * @cfg {String} altFormats
38850 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38851 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38853 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38855 * @cfg {Array} disabledDays
38856 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38858 disabledDays : [0,1,2,3,4,5,6],
38860 * @cfg {String} disabledDaysText
38861 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38863 disabledDaysText : "Disabled",
38865 * @cfg {Array} disabledDates
38866 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38867 * expression so they are very powerful. Some examples:
38869 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38870 * <li>["03/08", "09/16"] would disable those days for every year</li>
38871 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38872 * <li>["03/../2006"] would disable every day in March 2006</li>
38873 * <li>["^03"] would disable every day in every March</li>
38875 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38876 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38878 disabledDates : null,
38880 * @cfg {String} disabledDatesText
38881 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38883 disabledDatesText : "Disabled",
38885 * @cfg {Date/String} minValue
38886 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38887 * valid format (defaults to null).
38891 * @cfg {Date/String} maxValue
38892 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38893 * valid format (defaults to null).
38897 * @cfg {String} minText
38898 * The error text to display when the date in the cell is before minValue (defaults to
38899 * 'The date in this field must be after {minValue}').
38901 minText : "The date in this field must be equal to or after {0}",
38903 * @cfg {String} maxTextf
38904 * The error text to display when the date in the cell is after maxValue (defaults to
38905 * 'The date in this field must be before {maxValue}').
38907 maxText : "The date in this field must be equal to or before {0}",
38909 * @cfg {String} invalidText
38910 * The error text to display when the date in the field is invalid (defaults to
38911 * '{value} is not a valid date - it must be in the format {format}').
38913 invalidText : "{0} is not a valid date - it must be in the format {1}",
38915 * @cfg {String} triggerClass
38916 * An additional CSS class used to style the trigger button. The trigger will always get the
38917 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38918 * which displays a calendar icon).
38920 triggerClass : 'x-form-date-trigger',
38924 * @cfg {Boolean} useIso
38925 * if enabled, then the date field will use a hidden field to store the
38926 * real value as iso formated date. default (true)
38930 * @cfg {String/Object} autoCreate
38931 * A DomHelper element spec, or true for a default element spec (defaults to
38932 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38935 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38938 hiddenField: false,
38940 hideMonthPicker : false,
38942 onRender : function(ct, position)
38944 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38946 this.el.dom.removeAttribute('name');
38947 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38949 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38950 // prevent input submission
38951 this.hiddenName = this.name;
38958 validateValue : function(value)
38960 value = this.formatDate(value);
38961 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38964 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38967 var svalue = value;
38968 value = this.parseDate(value);
38970 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38973 var time = value.getTime();
38974 if(this.minValue && time < this.minValue.getTime()){
38975 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38978 if(this.maxValue && time > this.maxValue.getTime()){
38979 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38982 /*if(this.disabledDays){
38983 var day = value.getDay();
38984 for(var i = 0; i < this.disabledDays.length; i++) {
38985 if(day === this.disabledDays[i]){
38986 this.markInvalid(this.disabledDaysText);
38992 var fvalue = this.formatDate(value);
38993 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38994 this.markInvalid(String.format(this.disabledDatesText, fvalue));
39002 // Provides logic to override the default TriggerField.validateBlur which just returns true
39003 validateBlur : function(){
39004 return !this.menu || !this.menu.isVisible();
39008 * Returns the current date value of the date field.
39009 * @return {Date} The date value
39011 getValue : function(){
39015 return this.hiddenField ?
39016 this.hiddenField.value :
39017 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
39021 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
39022 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
39023 * (the default format used is "m/d/y").
39026 //All of these calls set the same date value (May 4, 2006)
39028 //Pass a date object:
39029 var dt = new Date('5/4/06');
39030 monthField.setValue(dt);
39032 //Pass a date string (default format):
39033 monthField.setValue('5/4/06');
39035 //Pass a date string (custom format):
39036 monthField.format = 'Y-m-d';
39037 monthField.setValue('2006-5-4');
39039 * @param {String/Date} date The date or valid date string
39041 setValue : function(date){
39042 Roo.log('month setValue' + date);
39043 // can only be first of month..
39045 var val = this.parseDate(date);
39047 if (this.hiddenField) {
39048 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
39050 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
39051 this.value = this.parseDate(date);
39055 parseDate : function(value){
39056 if(!value || value instanceof Date){
39057 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39060 var v = Date.parseDate(value, this.format);
39061 if (!v && this.useIso) {
39062 v = Date.parseDate(value, 'Y-m-d');
39066 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39070 if(!v && this.altFormats){
39071 if(!this.altFormatsArray){
39072 this.altFormatsArray = this.altFormats.split("|");
39074 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39075 v = Date.parseDate(value, this.altFormatsArray[i]);
39082 formatDate : function(date, fmt){
39083 return (!date || !(date instanceof Date)) ?
39084 date : date.dateFormat(fmt || this.format);
39089 select: function(m, d){
39091 this.fireEvent('select', this, d);
39093 show : function(){ // retain focus styling
39097 this.focus.defer(10, this);
39098 var ml = this.menuListeners;
39099 this.menu.un("select", ml.select, this);
39100 this.menu.un("show", ml.show, this);
39101 this.menu.un("hide", ml.hide, this);
39105 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39106 onTriggerClick : function(){
39110 if(this.menu == null){
39111 this.menu = new Roo.menu.DateMenu();
39115 Roo.apply(this.menu.picker, {
39117 showClear: this.allowBlank,
39118 minDate : this.minValue,
39119 maxDate : this.maxValue,
39120 disabledDatesRE : this.ddMatch,
39121 disabledDatesText : this.disabledDatesText,
39123 format : this.useIso ? 'Y-m-d' : this.format,
39124 minText : String.format(this.minText, this.formatDate(this.minValue)),
39125 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39128 this.menu.on(Roo.apply({}, this.menuListeners, {
39136 // hide month picker get's called when we called by 'before hide';
39138 var ignorehide = true;
39139 p.hideMonthPicker = function(disableAnim){
39143 if(this.monthPicker){
39144 Roo.log("hideMonthPicker called");
39145 if(disableAnim === true){
39146 this.monthPicker.hide();
39148 this.monthPicker.slideOut('t', {duration:.2});
39149 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39150 p.fireEvent("select", this, this.value);
39156 Roo.log('picker set value');
39157 Roo.log(this.getValue());
39158 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39159 m.show(this.el, 'tl-bl?');
39160 ignorehide = false;
39161 // this will trigger hideMonthPicker..
39164 // hidden the day picker
39165 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39171 p.showMonthPicker.defer(100, p);
39177 beforeBlur : function(){
39178 var v = this.parseDate(this.getRawValue());
39184 /** @cfg {Boolean} grow @hide */
39185 /** @cfg {Number} growMin @hide */
39186 /** @cfg {Number} growMax @hide */
39193 * Ext JS Library 1.1.1
39194 * Copyright(c) 2006-2007, Ext JS, LLC.
39196 * Originally Released Under LGPL - original licence link has changed is not relivant.
39199 * <script type="text/javascript">
39204 * @class Roo.form.ComboBox
39205 * @extends Roo.form.TriggerField
39206 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39208 * Create a new ComboBox.
39209 * @param {Object} config Configuration options
39211 Roo.form.ComboBox = function(config){
39212 Roo.form.ComboBox.superclass.constructor.call(this, config);
39216 * Fires when the dropdown list is expanded
39217 * @param {Roo.form.ComboBox} combo This combo box
39222 * Fires when the dropdown list is collapsed
39223 * @param {Roo.form.ComboBox} combo This combo box
39227 * @event beforeselect
39228 * Fires before a list item is selected. Return false to cancel the selection.
39229 * @param {Roo.form.ComboBox} combo This combo box
39230 * @param {Roo.data.Record} record The data record returned from the underlying store
39231 * @param {Number} index The index of the selected item in the dropdown list
39233 'beforeselect' : true,
39236 * Fires when a list item is selected
39237 * @param {Roo.form.ComboBox} combo This combo box
39238 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39239 * @param {Number} index The index of the selected item in the dropdown list
39243 * @event beforequery
39244 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39245 * The event object passed has these properties:
39246 * @param {Roo.form.ComboBox} combo This combo box
39247 * @param {String} query The query
39248 * @param {Boolean} forceAll true to force "all" query
39249 * @param {Boolean} cancel true to cancel the query
39250 * @param {Object} e The query event object
39252 'beforequery': true,
39255 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39256 * @param {Roo.form.ComboBox} combo This combo box
39261 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39262 * @param {Roo.form.ComboBox} combo This combo box
39263 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39269 if(this.transform){
39270 this.allowDomMove = false;
39271 var s = Roo.getDom(this.transform);
39272 if(!this.hiddenName){
39273 this.hiddenName = s.name;
39276 this.mode = 'local';
39277 var d = [], opts = s.options;
39278 for(var i = 0, len = opts.length;i < len; i++){
39280 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39282 this.value = value;
39284 d.push([value, o.text]);
39286 this.store = new Roo.data.SimpleStore({
39288 fields: ['value', 'text'],
39291 this.valueField = 'value';
39292 this.displayField = 'text';
39294 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39295 if(!this.lazyRender){
39296 this.target = true;
39297 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39298 s.parentNode.removeChild(s); // remove it
39299 this.render(this.el.parentNode);
39301 s.parentNode.removeChild(s); // remove it
39306 this.store = Roo.factory(this.store, Roo.data);
39309 this.selectedIndex = -1;
39310 if(this.mode == 'local'){
39311 if(config.queryDelay === undefined){
39312 this.queryDelay = 10;
39314 if(config.minChars === undefined){
39320 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39322 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39325 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39326 * rendering into an Roo.Editor, defaults to false)
39329 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39330 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39333 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39336 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39337 * the dropdown list (defaults to undefined, with no header element)
39341 * @cfg {String/Roo.Template} tpl The template to use to render the output
39345 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39347 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39349 listWidth: undefined,
39351 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39352 * mode = 'remote' or 'text' if mode = 'local')
39354 displayField: undefined,
39356 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39357 * mode = 'remote' or 'value' if mode = 'local').
39358 * Note: use of a valueField requires the user make a selection
39359 * in order for a value to be mapped.
39361 valueField: undefined,
39365 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39366 * field's data value (defaults to the underlying DOM element's name)
39368 hiddenName: undefined,
39370 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39374 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39376 selectedClass: 'x-combo-selected',
39378 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39379 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39380 * which displays a downward arrow icon).
39382 triggerClass : 'x-form-arrow-trigger',
39384 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39388 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39389 * anchor positions (defaults to 'tl-bl')
39391 listAlign: 'tl-bl?',
39393 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39397 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39398 * query specified by the allQuery config option (defaults to 'query')
39400 triggerAction: 'query',
39402 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39403 * (defaults to 4, does not apply if editable = false)
39407 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39408 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39412 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39413 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39417 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39418 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39422 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39423 * when editable = true (defaults to false)
39425 selectOnFocus:false,
39427 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39429 queryParam: 'query',
39431 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39432 * when mode = 'remote' (defaults to 'Loading...')
39434 loadingText: 'Loading...',
39436 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39440 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39444 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39445 * traditional select (defaults to true)
39449 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39453 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39457 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39458 * listWidth has a higher value)
39462 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39463 * allow the user to set arbitrary text into the field (defaults to false)
39465 forceSelection:false,
39467 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39468 * if typeAhead = true (defaults to 250)
39470 typeAheadDelay : 250,
39472 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39473 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39475 valueNotFoundText : undefined,
39477 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39479 blockFocus : false,
39482 * @cfg {Boolean} disableClear Disable showing of clear button.
39484 disableClear : false,
39486 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39488 alwaysQuery : false,
39494 // element that contains real text value.. (when hidden is used..)
39497 onRender : function(ct, position){
39498 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39499 if(this.hiddenName){
39500 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39502 this.hiddenField.value =
39503 this.hiddenValue !== undefined ? this.hiddenValue :
39504 this.value !== undefined ? this.value : '';
39506 // prevent input submission
39507 this.el.dom.removeAttribute('name');
39512 this.el.dom.setAttribute('autocomplete', 'off');
39515 var cls = 'x-combo-list';
39517 this.list = new Roo.Layer({
39518 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39521 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39522 this.list.setWidth(lw);
39523 this.list.swallowEvent('mousewheel');
39524 this.assetHeight = 0;
39527 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39528 this.assetHeight += this.header.getHeight();
39531 this.innerList = this.list.createChild({cls:cls+'-inner'});
39532 this.innerList.on('mouseover', this.onViewOver, this);
39533 this.innerList.on('mousemove', this.onViewMove, this);
39534 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39536 if(this.allowBlank && !this.pageSize && !this.disableClear){
39537 this.footer = this.list.createChild({cls:cls+'-ft'});
39538 this.pageTb = new Roo.Toolbar(this.footer);
39542 this.footer = this.list.createChild({cls:cls+'-ft'});
39543 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39544 {pageSize: this.pageSize});
39548 if (this.pageTb && this.allowBlank && !this.disableClear) {
39550 this.pageTb.add(new Roo.Toolbar.Fill(), {
39551 cls: 'x-btn-icon x-btn-clear',
39553 handler: function()
39556 _this.clearValue();
39557 _this.onSelect(false, -1);
39562 this.assetHeight += this.footer.getHeight();
39567 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39570 this.view = new Roo.View(this.innerList, this.tpl, {
39571 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39574 this.view.on('click', this.onViewClick, this);
39576 this.store.on('beforeload', this.onBeforeLoad, this);
39577 this.store.on('load', this.onLoad, this);
39578 this.store.on('loadexception', this.onLoadException, this);
39580 if(this.resizable){
39581 this.resizer = new Roo.Resizable(this.list, {
39582 pinned:true, handles:'se'
39584 this.resizer.on('resize', function(r, w, h){
39585 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39586 this.listWidth = w;
39587 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39588 this.restrictHeight();
39590 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39592 if(!this.editable){
39593 this.editable = true;
39594 this.setEditable(false);
39598 if (typeof(this.events.add.listeners) != 'undefined') {
39600 this.addicon = this.wrap.createChild(
39601 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39603 this.addicon.on('click', function(e) {
39604 this.fireEvent('add', this);
39607 if (typeof(this.events.edit.listeners) != 'undefined') {
39609 this.editicon = this.wrap.createChild(
39610 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39611 if (this.addicon) {
39612 this.editicon.setStyle('margin-left', '40px');
39614 this.editicon.on('click', function(e) {
39616 // we fire even if inothing is selected..
39617 this.fireEvent('edit', this, this.lastData );
39627 initEvents : function(){
39628 Roo.form.ComboBox.superclass.initEvents.call(this);
39630 this.keyNav = new Roo.KeyNav(this.el, {
39631 "up" : function(e){
39632 this.inKeyMode = true;
39636 "down" : function(e){
39637 if(!this.isExpanded()){
39638 this.onTriggerClick();
39640 this.inKeyMode = true;
39645 "enter" : function(e){
39646 this.onViewClick();
39650 "esc" : function(e){
39654 "tab" : function(e){
39655 this.onViewClick(false);
39656 this.fireEvent("specialkey", this, e);
39662 doRelay : function(foo, bar, hname){
39663 if(hname == 'down' || this.scope.isExpanded()){
39664 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39671 this.queryDelay = Math.max(this.queryDelay || 10,
39672 this.mode == 'local' ? 10 : 250);
39673 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39674 if(this.typeAhead){
39675 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39677 if(this.editable !== false){
39678 this.el.on("keyup", this.onKeyUp, this);
39680 if(this.forceSelection){
39681 this.on('blur', this.doForce, this);
39685 onDestroy : function(){
39687 this.view.setStore(null);
39688 this.view.el.removeAllListeners();
39689 this.view.el.remove();
39690 this.view.purgeListeners();
39693 this.list.destroy();
39696 this.store.un('beforeload', this.onBeforeLoad, this);
39697 this.store.un('load', this.onLoad, this);
39698 this.store.un('loadexception', this.onLoadException, this);
39700 Roo.form.ComboBox.superclass.onDestroy.call(this);
39704 fireKey : function(e){
39705 if(e.isNavKeyPress() && !this.list.isVisible()){
39706 this.fireEvent("specialkey", this, e);
39711 onResize: function(w, h){
39712 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39714 if(typeof w != 'number'){
39715 // we do not handle it!?!?
39718 var tw = this.trigger.getWidth();
39719 tw += this.addicon ? this.addicon.getWidth() : 0;
39720 tw += this.editicon ? this.editicon.getWidth() : 0;
39722 this.el.setWidth( this.adjustWidth('input', x));
39724 this.trigger.setStyle('left', x+'px');
39726 if(this.list && this.listWidth === undefined){
39727 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39728 this.list.setWidth(lw);
39729 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39737 * Allow or prevent the user from directly editing the field text. If false is passed,
39738 * the user will only be able to select from the items defined in the dropdown list. This method
39739 * is the runtime equivalent of setting the 'editable' config option at config time.
39740 * @param {Boolean} value True to allow the user to directly edit the field text
39742 setEditable : function(value){
39743 if(value == this.editable){
39746 this.editable = value;
39748 this.el.dom.setAttribute('readOnly', true);
39749 this.el.on('mousedown', this.onTriggerClick, this);
39750 this.el.addClass('x-combo-noedit');
39752 this.el.dom.setAttribute('readOnly', false);
39753 this.el.un('mousedown', this.onTriggerClick, this);
39754 this.el.removeClass('x-combo-noedit');
39759 onBeforeLoad : function(){
39760 if(!this.hasFocus){
39763 this.innerList.update(this.loadingText ?
39764 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39765 this.restrictHeight();
39766 this.selectedIndex = -1;
39770 onLoad : function(){
39771 if(!this.hasFocus){
39774 if(this.store.getCount() > 0){
39776 this.restrictHeight();
39777 if(this.lastQuery == this.allQuery){
39779 this.el.dom.select();
39781 if(!this.selectByValue(this.value, true)){
39782 this.select(0, true);
39786 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39787 this.taTask.delay(this.typeAheadDelay);
39791 this.onEmptyResults();
39796 onLoadException : function()
39799 Roo.log(this.store.reader.jsonData);
39800 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39801 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39807 onTypeAhead : function(){
39808 if(this.store.getCount() > 0){
39809 var r = this.store.getAt(0);
39810 var newValue = r.data[this.displayField];
39811 var len = newValue.length;
39812 var selStart = this.getRawValue().length;
39813 if(selStart != len){
39814 this.setRawValue(newValue);
39815 this.selectText(selStart, newValue.length);
39821 onSelect : function(record, index){
39822 if(this.fireEvent('beforeselect', this, record, index) !== false){
39823 this.setFromData(index > -1 ? record.data : false);
39825 this.fireEvent('select', this, record, index);
39830 * Returns the currently selected field value or empty string if no value is set.
39831 * @return {String} value The selected value
39833 getValue : function(){
39834 if(this.valueField){
39835 return typeof this.value != 'undefined' ? this.value : '';
39837 return Roo.form.ComboBox.superclass.getValue.call(this);
39841 * Clears any text/value currently set in the field
39843 clearValue : function(){
39844 if(this.hiddenField){
39845 this.hiddenField.value = '';
39848 this.setRawValue('');
39849 this.lastSelectionText = '';
39854 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39855 * will be displayed in the field. If the value does not match the data value of an existing item,
39856 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39857 * Otherwise the field will be blank (although the value will still be set).
39858 * @param {String} value The value to match
39860 setValue : function(v){
39862 if(this.valueField){
39863 var r = this.findRecord(this.valueField, v);
39865 text = r.data[this.displayField];
39866 }else if(this.valueNotFoundText !== undefined){
39867 text = this.valueNotFoundText;
39870 this.lastSelectionText = text;
39871 if(this.hiddenField){
39872 this.hiddenField.value = v;
39874 Roo.form.ComboBox.superclass.setValue.call(this, text);
39878 * @property {Object} the last set data for the element
39883 * Sets the value of the field based on a object which is related to the record format for the store.
39884 * @param {Object} value the value to set as. or false on reset?
39886 setFromData : function(o){
39887 var dv = ''; // display value
39888 var vv = ''; // value value..
39890 if (this.displayField) {
39891 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39893 // this is an error condition!!!
39894 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39897 if(this.valueField){
39898 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39900 if(this.hiddenField){
39901 this.hiddenField.value = vv;
39903 this.lastSelectionText = dv;
39904 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39908 // no hidden field.. - we store the value in 'value', but still display
39909 // display field!!!!
39910 this.lastSelectionText = dv;
39911 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39917 reset : function(){
39918 // overridden so that last data is reset..
39919 this.setValue(this.resetValue);
39920 this.clearInvalid();
39921 this.lastData = false;
39923 this.view.clearSelections();
39927 findRecord : function(prop, value){
39929 if(this.store.getCount() > 0){
39930 this.store.each(function(r){
39931 if(r.data[prop] == value){
39941 getName: function()
39943 // returns hidden if it's set..
39944 if (!this.rendered) {return ''};
39945 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39949 onViewMove : function(e, t){
39950 this.inKeyMode = false;
39954 onViewOver : function(e, t){
39955 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39958 var item = this.view.findItemFromChild(t);
39960 var index = this.view.indexOf(item);
39961 this.select(index, false);
39966 onViewClick : function(doFocus)
39968 var index = this.view.getSelectedIndexes()[0];
39969 var r = this.store.getAt(index);
39971 this.onSelect(r, index);
39973 if(doFocus !== false && !this.blockFocus){
39979 restrictHeight : function(){
39980 this.innerList.dom.style.height = '';
39981 var inner = this.innerList.dom;
39982 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39983 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39984 this.list.beginUpdate();
39985 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39986 this.list.alignTo(this.el, this.listAlign);
39987 this.list.endUpdate();
39991 onEmptyResults : function(){
39996 * Returns true if the dropdown list is expanded, else false.
39998 isExpanded : function(){
39999 return this.list.isVisible();
40003 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
40004 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40005 * @param {String} value The data value of the item to select
40006 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40007 * selected item if it is not currently in view (defaults to true)
40008 * @return {Boolean} True if the value matched an item in the list, else false
40010 selectByValue : function(v, scrollIntoView){
40011 if(v !== undefined && v !== null){
40012 var r = this.findRecord(this.valueField || this.displayField, v);
40014 this.select(this.store.indexOf(r), scrollIntoView);
40022 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
40023 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40024 * @param {Number} index The zero-based index of the list item to select
40025 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40026 * selected item if it is not currently in view (defaults to true)
40028 select : function(index, scrollIntoView){
40029 this.selectedIndex = index;
40030 this.view.select(index);
40031 if(scrollIntoView !== false){
40032 var el = this.view.getNode(index);
40034 this.innerList.scrollChildIntoView(el, false);
40040 selectNext : function(){
40041 var ct = this.store.getCount();
40043 if(this.selectedIndex == -1){
40045 }else if(this.selectedIndex < ct-1){
40046 this.select(this.selectedIndex+1);
40052 selectPrev : function(){
40053 var ct = this.store.getCount();
40055 if(this.selectedIndex == -1){
40057 }else if(this.selectedIndex != 0){
40058 this.select(this.selectedIndex-1);
40064 onKeyUp : function(e){
40065 if(this.editable !== false && !e.isSpecialKey()){
40066 this.lastKey = e.getKey();
40067 this.dqTask.delay(this.queryDelay);
40072 validateBlur : function(){
40073 return !this.list || !this.list.isVisible();
40077 initQuery : function(){
40078 this.doQuery(this.getRawValue());
40082 doForce : function(){
40083 if(this.el.dom.value.length > 0){
40084 this.el.dom.value =
40085 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40091 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40092 * query allowing the query action to be canceled if needed.
40093 * @param {String} query The SQL query to execute
40094 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40095 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40096 * saved in the current store (defaults to false)
40098 doQuery : function(q, forceAll){
40099 if(q === undefined || q === null){
40104 forceAll: forceAll,
40108 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40112 forceAll = qe.forceAll;
40113 if(forceAll === true || (q.length >= this.minChars)){
40114 if(this.lastQuery != q || this.alwaysQuery){
40115 this.lastQuery = q;
40116 if(this.mode == 'local'){
40117 this.selectedIndex = -1;
40119 this.store.clearFilter();
40121 this.store.filter(this.displayField, q);
40125 this.store.baseParams[this.queryParam] = q;
40127 params: this.getParams(q)
40132 this.selectedIndex = -1;
40139 getParams : function(q){
40141 //p[this.queryParam] = q;
40144 p.limit = this.pageSize;
40150 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40152 collapse : function(){
40153 if(!this.isExpanded()){
40157 Roo.get(document).un('mousedown', this.collapseIf, this);
40158 Roo.get(document).un('mousewheel', this.collapseIf, this);
40159 if (!this.editable) {
40160 Roo.get(document).un('keydown', this.listKeyPress, this);
40162 this.fireEvent('collapse', this);
40166 collapseIf : function(e){
40167 if(!e.within(this.wrap) && !e.within(this.list)){
40173 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40175 expand : function(){
40176 if(this.isExpanded() || !this.hasFocus){
40179 this.list.alignTo(this.el, this.listAlign);
40181 Roo.get(document).on('mousedown', this.collapseIf, this);
40182 Roo.get(document).on('mousewheel', this.collapseIf, this);
40183 if (!this.editable) {
40184 Roo.get(document).on('keydown', this.listKeyPress, this);
40187 this.fireEvent('expand', this);
40191 // Implements the default empty TriggerField.onTriggerClick function
40192 onTriggerClick : function(){
40196 if(this.isExpanded()){
40198 if (!this.blockFocus) {
40203 this.hasFocus = true;
40204 if(this.triggerAction == 'all') {
40205 this.doQuery(this.allQuery, true);
40207 this.doQuery(this.getRawValue());
40209 if (!this.blockFocus) {
40214 listKeyPress : function(e)
40216 //Roo.log('listkeypress');
40217 // scroll to first matching element based on key pres..
40218 if (e.isSpecialKey()) {
40221 var k = String.fromCharCode(e.getKey()).toUpperCase();
40224 var csel = this.view.getSelectedNodes();
40225 var cselitem = false;
40227 var ix = this.view.indexOf(csel[0]);
40228 cselitem = this.store.getAt(ix);
40229 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40235 this.store.each(function(v) {
40237 // start at existing selection.
40238 if (cselitem.id == v.id) {
40244 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40245 match = this.store.indexOf(v);
40250 if (match === false) {
40251 return true; // no more action?
40254 this.view.select(match);
40255 var sn = Roo.get(this.view.getSelectedNodes()[0])
40256 sn.scrollIntoView(sn.dom.parentNode, false);
40260 * @cfg {Boolean} grow
40264 * @cfg {Number} growMin
40268 * @cfg {Number} growMax
40276 * Copyright(c) 2010-2012, Roo J Solutions Limited
40283 * @class Roo.form.ComboBoxArray
40284 * @extends Roo.form.TextField
40285 * A facebook style adder... for lists of email / people / countries etc...
40286 * pick multiple items from a combo box, and shows each one.
40288 * Fred [x] Brian [x] [Pick another |v]
40291 * For this to work: it needs various extra information
40292 * - normal combo problay has
40294 * + displayField, valueField
40296 * For our purpose...
40299 * If we change from 'extends' to wrapping...
40306 * Create a new ComboBoxArray.
40307 * @param {Object} config Configuration options
40311 Roo.form.ComboBoxArray = function(config)
40316 * Fires when remove the value from the list
40317 * @param {Roo.form.ComboBoxArray} _self This combo box array
40318 * @param {Roo.form.ComboBoxArray.Item} item removed item
40325 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40327 this.items = new Roo.util.MixedCollection(false);
40329 // construct the child combo...
40339 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40342 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40347 // behavies liek a hiddne field
40348 inputType: 'hidden',
40350 * @cfg {Number} width The width of the box that displays the selected element
40357 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40361 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40363 hiddenName : false,
40366 // private the array of items that are displayed..
40368 // private - the hidden field el.
40370 // private - the filed el..
40373 //validateValue : function() { return true; }, // all values are ok!
40374 //onAddClick: function() { },
40376 onRender : function(ct, position)
40379 // create the standard hidden element
40380 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40383 // give fake names to child combo;
40384 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40385 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40387 this.combo = Roo.factory(this.combo, Roo.form);
40388 this.combo.onRender(ct, position);
40389 if (typeof(this.combo.width) != 'undefined') {
40390 this.combo.onResize(this.combo.width,0);
40393 this.combo.initEvents();
40395 // assigned so form know we need to do this..
40396 this.store = this.combo.store;
40397 this.valueField = this.combo.valueField;
40398 this.displayField = this.combo.displayField ;
40401 this.combo.wrap.addClass('x-cbarray-grp');
40403 var cbwrap = this.combo.wrap.createChild(
40404 {tag: 'div', cls: 'x-cbarray-cb'},
40409 this.hiddenEl = this.combo.wrap.createChild({
40410 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40412 this.el = this.combo.wrap.createChild({
40413 tag: 'input', type:'hidden' , name: this.name, value : ''
40415 // this.el.dom.removeAttribute("name");
40418 this.outerWrap = this.combo.wrap;
40419 this.wrap = cbwrap;
40421 this.outerWrap.setWidth(this.width);
40422 this.outerWrap.dom.removeChild(this.el.dom);
40424 this.wrap.dom.appendChild(this.el.dom);
40425 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40426 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40428 this.combo.trigger.setStyle('position','relative');
40429 this.combo.trigger.setStyle('left', '0px');
40430 this.combo.trigger.setStyle('top', '2px');
40432 this.combo.el.setStyle('vertical-align', 'text-bottom');
40434 //this.trigger.setStyle('vertical-align', 'top');
40436 // this should use the code from combo really... on('add' ....)
40440 this.adder = this.outerWrap.createChild(
40441 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40443 this.adder.on('click', function(e) {
40444 _t.fireEvent('adderclick', this, e);
40448 //this.adder.on('click', this.onAddClick, _t);
40451 this.combo.on('select', function(cb, rec, ix) {
40452 this.addItem(rec.data);
40455 cb.el.dom.value = '';
40456 //cb.lastData = rec.data;
40465 getName: function()
40467 // returns hidden if it's set..
40468 if (!this.rendered) {return ''};
40469 return this.hiddenName ? this.hiddenName : this.name;
40474 onResize: function(w, h){
40477 // not sure if this is needed..
40478 //this.combo.onResize(w,h);
40480 if(typeof w != 'number'){
40481 // we do not handle it!?!?
40484 var tw = this.combo.trigger.getWidth();
40485 tw += this.addicon ? this.addicon.getWidth() : 0;
40486 tw += this.editicon ? this.editicon.getWidth() : 0;
40488 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40490 this.combo.trigger.setStyle('left', '0px');
40492 if(this.list && this.listWidth === undefined){
40493 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40494 this.list.setWidth(lw);
40495 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40502 addItem: function(rec)
40504 var valueField = this.combo.valueField;
40505 var displayField = this.combo.displayField;
40506 if (this.items.indexOfKey(rec[valueField]) > -1) {
40507 //console.log("GOT " + rec.data.id);
40511 var x = new Roo.form.ComboBoxArray.Item({
40512 //id : rec[this.idField],
40514 displayField : displayField ,
40515 tipField : displayField ,
40519 this.items.add(rec[valueField],x);
40520 // add it before the element..
40521 this.updateHiddenEl();
40522 x.render(this.outerWrap, this.wrap.dom);
40523 // add the image handler..
40526 updateHiddenEl : function()
40529 if (!this.hiddenEl) {
40533 var idField = this.combo.valueField;
40535 this.items.each(function(f) {
40536 ar.push(f.data[idField]);
40539 this.hiddenEl.dom.value = ar.join(',');
40545 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40546 this.items.each(function(f) {
40549 this.el.dom.value = '';
40550 if (this.hiddenEl) {
40551 this.hiddenEl.dom.value = '';
40555 getValue: function()
40557 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40559 setValue: function(v) // not a valid action - must use addItems..
40566 if (this.store.isLocal && (typeof(v) == 'string')) {
40567 // then we can use the store to find the values..
40568 // comma seperated at present.. this needs to allow JSON based encoding..
40569 this.hiddenEl.value = v;
40571 Roo.each(v.split(','), function(k) {
40572 Roo.log("CHECK " + this.valueField + ',' + k);
40573 var li = this.store.query(this.valueField, k);
40578 add[this.valueField] = k;
40579 add[this.displayField] = li.item(0).data[this.displayField];
40585 if (typeof(v) == 'object' ) {
40586 // then let's assume it's an array of objects..
40587 Roo.each(v, function(l) {
40595 setFromData: function(v)
40597 // this recieves an object, if setValues is called.
40599 this.el.dom.value = v[this.displayField];
40600 this.hiddenEl.dom.value = v[this.valueField];
40601 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40604 var kv = v[this.valueField];
40605 var dv = v[this.displayField];
40606 kv = typeof(kv) != 'string' ? '' : kv;
40607 dv = typeof(dv) != 'string' ? '' : dv;
40610 var keys = kv.split(',');
40611 var display = dv.split(',');
40612 for (var i = 0 ; i < keys.length; i++) {
40615 add[this.valueField] = keys[i];
40616 add[this.displayField] = display[i];
40624 * Validates the combox array value
40625 * @return {Boolean} True if the value is valid, else false
40627 validate : function(){
40628 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40629 this.clearInvalid();
40635 validateValue : function(value){
40636 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40644 isDirty : function() {
40645 if(this.disabled) {
40650 var d = Roo.decode(String(this.originalValue));
40652 return String(this.getValue()) !== String(this.originalValue);
40655 var originalValue = [];
40657 for (var i = 0; i < d.length; i++){
40658 originalValue.push(d[i][this.valueField]);
40661 return String(this.getValue()) !== String(originalValue.join(','));
40670 * @class Roo.form.ComboBoxArray.Item
40671 * @extends Roo.BoxComponent
40672 * A selected item in the list
40673 * Fred [x] Brian [x] [Pick another |v]
40676 * Create a new item.
40677 * @param {Object} config Configuration options
40680 Roo.form.ComboBoxArray.Item = function(config) {
40681 config.id = Roo.id();
40682 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40685 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40688 displayField : false,
40692 defaultAutoCreate : {
40694 cls: 'x-cbarray-item',
40701 src : Roo.BLANK_IMAGE_URL ,
40709 onRender : function(ct, position)
40711 Roo.form.Field.superclass.onRender.call(this, ct, position);
40714 var cfg = this.getAutoCreate();
40715 this.el = ct.createChild(cfg, position);
40718 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40720 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40721 this.cb.renderer(this.data) :
40722 String.format('{0}',this.data[this.displayField]);
40725 this.el.child('div').dom.setAttribute('qtip',
40726 String.format('{0}',this.data[this.tipField])
40729 this.el.child('img').on('click', this.remove, this);
40733 remove : function()
40735 this.cb.items.remove(this);
40736 this.el.child('img').un('click', this.remove, this);
40738 this.cb.updateHiddenEl();
40740 this.cb.fireEvent('remove', this.cb, this);
40744 * Ext JS Library 1.1.1
40745 * Copyright(c) 2006-2007, Ext JS, LLC.
40747 * Originally Released Under LGPL - original licence link has changed is not relivant.
40750 * <script type="text/javascript">
40753 * @class Roo.form.Checkbox
40754 * @extends Roo.form.Field
40755 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40757 * Creates a new Checkbox
40758 * @param {Object} config Configuration options
40760 Roo.form.Checkbox = function(config){
40761 Roo.form.Checkbox.superclass.constructor.call(this, config);
40765 * Fires when the checkbox is checked or unchecked.
40766 * @param {Roo.form.Checkbox} this This checkbox
40767 * @param {Boolean} checked The new checked value
40773 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40775 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40777 focusClass : undefined,
40779 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40781 fieldClass: "x-form-field",
40783 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40787 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40788 * {tag: "input", type: "checkbox", autocomplete: "off"})
40790 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40792 * @cfg {String} boxLabel The text that appears beside the checkbox
40796 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40800 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40802 valueOff: '0', // value when not checked..
40804 actionMode : 'viewEl',
40807 itemCls : 'x-menu-check-item x-form-item',
40808 groupClass : 'x-menu-group-item',
40809 inputType : 'hidden',
40812 inSetChecked: false, // check that we are not calling self...
40814 inputElement: false, // real input element?
40815 basedOn: false, // ????
40817 isFormField: true, // not sure where this is needed!!!!
40819 onResize : function(){
40820 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40821 if(!this.boxLabel){
40822 this.el.alignTo(this.wrap, 'c-c');
40826 initEvents : function(){
40827 Roo.form.Checkbox.superclass.initEvents.call(this);
40828 this.el.on("click", this.onClick, this);
40829 this.el.on("change", this.onClick, this);
40833 getResizeEl : function(){
40837 getPositionEl : function(){
40842 onRender : function(ct, position){
40843 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40845 if(this.inputValue !== undefined){
40846 this.el.dom.value = this.inputValue;
40849 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40850 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40851 var viewEl = this.wrap.createChild({
40852 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40853 this.viewEl = viewEl;
40854 this.wrap.on('click', this.onClick, this);
40856 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40857 this.el.on('propertychange', this.setFromHidden, this); //ie
40862 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40863 // viewEl.on('click', this.onClick, this);
40865 //if(this.checked){
40866 this.setChecked(this.checked);
40868 //this.checked = this.el.dom;
40874 initValue : Roo.emptyFn,
40877 * Returns the checked state of the checkbox.
40878 * @return {Boolean} True if checked, else false
40880 getValue : function(){
40882 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40884 return this.valueOff;
40889 onClick : function(){
40890 this.setChecked(!this.checked);
40892 //if(this.el.dom.checked != this.checked){
40893 // this.setValue(this.el.dom.checked);
40898 * Sets the checked state of the checkbox.
40899 * On is always based on a string comparison between inputValue and the param.
40900 * @param {Boolean/String} value - the value to set
40901 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40903 setValue : function(v,suppressEvent){
40906 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40907 //if(this.el && this.el.dom){
40908 // this.el.dom.checked = this.checked;
40909 // this.el.dom.defaultChecked = this.checked;
40911 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40912 //this.fireEvent("check", this, this.checked);
40915 setChecked : function(state,suppressEvent)
40917 if (this.inSetChecked) {
40918 this.checked = state;
40924 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40926 this.checked = state;
40927 if(suppressEvent !== true){
40928 this.fireEvent('check', this, state);
40930 this.inSetChecked = true;
40931 this.el.dom.value = state ? this.inputValue : this.valueOff;
40932 this.inSetChecked = false;
40935 // handle setting of hidden value by some other method!!?!?
40936 setFromHidden: function()
40941 //console.log("SET FROM HIDDEN");
40942 //alert('setFrom hidden');
40943 this.setValue(this.el.dom.value);
40946 onDestroy : function()
40949 Roo.get(this.viewEl).remove();
40952 Roo.form.Checkbox.superclass.onDestroy.call(this);
40957 * Ext JS Library 1.1.1
40958 * Copyright(c) 2006-2007, Ext JS, LLC.
40960 * Originally Released Under LGPL - original licence link has changed is not relivant.
40963 * <script type="text/javascript">
40967 * @class Roo.form.Radio
40968 * @extends Roo.form.Checkbox
40969 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40970 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40972 * Creates a new Radio
40973 * @param {Object} config Configuration options
40975 Roo.form.Radio = function(){
40976 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40978 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40979 inputType: 'radio',
40982 * If this radio is part of a group, it will return the selected value
40985 getGroupValue : function(){
40986 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40990 onRender : function(ct, position){
40991 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40993 if(this.inputValue !== undefined){
40994 this.el.dom.value = this.inputValue;
40997 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40998 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40999 //var viewEl = this.wrap.createChild({
41000 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41001 //this.viewEl = viewEl;
41002 //this.wrap.on('click', this.onClick, this);
41004 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41005 //this.el.on('propertychange', this.setFromHidden, this); //ie
41010 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41011 // viewEl.on('click', this.onClick, this);
41014 this.el.dom.checked = 'checked' ;
41020 });//<script type="text/javascript">
41023 * Based Ext JS Library 1.1.1
41024 * Copyright(c) 2006-2007, Ext JS, LLC.
41030 * @class Roo.HtmlEditorCore
41031 * @extends Roo.Component
41032 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41034 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41037 Roo.HtmlEditorCore = function(config){
41040 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41045 * @event initialize
41046 * Fires when the editor is fully initialized (including the iframe)
41047 * @param {Roo.HtmlEditorCore} this
41052 * Fires when the editor is first receives the focus. Any insertion must wait
41053 * until after this event.
41054 * @param {Roo.HtmlEditorCore} this
41058 * @event beforesync
41059 * Fires before the textarea is updated with content from the editor iframe. Return false
41060 * to cancel the sync.
41061 * @param {Roo.HtmlEditorCore} this
41062 * @param {String} html
41066 * @event beforepush
41067 * Fires before the iframe editor is updated with content from the textarea. Return false
41068 * to cancel the push.
41069 * @param {Roo.HtmlEditorCore} this
41070 * @param {String} html
41075 * Fires when the textarea is updated with content from the editor iframe.
41076 * @param {Roo.HtmlEditorCore} this
41077 * @param {String} html
41082 * Fires when the iframe editor is updated with content from the textarea.
41083 * @param {Roo.HtmlEditorCore} this
41084 * @param {String} html
41089 * @event editorevent
41090 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41091 * @param {Roo.HtmlEditorCore} this
41096 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
41098 // defaults : white / black...
41099 this.applyBlacklists();
41106 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41110 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41116 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41121 * @cfg {Number} height (in pixels)
41125 * @cfg {Number} width (in pixels)
41130 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41133 stylesheets: false,
41138 // private properties
41139 validationEvent : false,
41141 initialized : false,
41143 sourceEditMode : false,
41144 onFocus : Roo.emptyFn,
41146 hideMode:'offsets',
41150 // blacklist + whitelisted elements..
41157 * Protected method that will not generally be called directly. It
41158 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41159 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41161 getDocMarkup : function(){
41164 Roo.log(this.stylesheets);
41166 // inherit styels from page...??
41167 if (this.stylesheets === false) {
41169 Roo.get(document.head).select('style').each(function(node) {
41170 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41173 Roo.get(document.head).select('link').each(function(node) {
41174 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41177 } else if (!this.stylesheets.length) {
41179 st = '<style type="text/css">' +
41180 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41183 Roo.each(this.stylesheets, function(s) {
41184 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
41189 st += '<style type="text/css">' +
41190 'IMG { cursor: pointer } ' +
41194 return '<html><head>' + st +
41195 //<style type="text/css">' +
41196 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41198 ' </head><body class="roo-htmleditor-body"></body></html>';
41202 onRender : function(ct, position)
41205 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41206 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41209 this.el.dom.style.border = '0 none';
41210 this.el.dom.setAttribute('tabIndex', -1);
41211 this.el.addClass('x-hidden hide');
41215 if(Roo.isIE){ // fix IE 1px bogus margin
41216 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41220 this.frameId = Roo.id();
41224 var iframe = this.owner.wrap.createChild({
41226 cls: 'form-control', // bootstrap..
41228 name: this.frameId,
41229 frameBorder : 'no',
41230 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41235 this.iframe = iframe.dom;
41237 this.assignDocWin();
41239 this.doc.designMode = 'on';
41242 this.doc.write(this.getDocMarkup());
41246 var task = { // must defer to wait for browser to be ready
41248 //console.log("run task?" + this.doc.readyState);
41249 this.assignDocWin();
41250 if(this.doc.body || this.doc.readyState == 'complete'){
41252 this.doc.designMode="on";
41256 Roo.TaskMgr.stop(task);
41257 this.initEditor.defer(10, this);
41264 Roo.TaskMgr.start(task);
41271 onResize : function(w, h)
41273 Roo.log('resize: ' +w + ',' + h );
41274 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41278 if(typeof w == 'number'){
41280 this.iframe.style.width = w + 'px';
41282 if(typeof h == 'number'){
41284 this.iframe.style.height = h + 'px';
41286 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41293 * Toggles the editor between standard and source edit mode.
41294 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41296 toggleSourceEdit : function(sourceEditMode){
41298 this.sourceEditMode = sourceEditMode === true;
41300 if(this.sourceEditMode){
41302 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41305 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41306 //this.iframe.className = '';
41309 //this.setSize(this.owner.wrap.getSize());
41310 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41317 * Protected method that will not generally be called directly. If you need/want
41318 * custom HTML cleanup, this is the method you should override.
41319 * @param {String} html The HTML to be cleaned
41320 * return {String} The cleaned HTML
41322 cleanHtml : function(html){
41323 html = String(html);
41324 if(html.length > 5){
41325 if(Roo.isSafari){ // strip safari nonsense
41326 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41329 if(html == ' '){
41336 * HTML Editor -> Textarea
41337 * Protected method that will not generally be called directly. Syncs the contents
41338 * of the editor iframe with the textarea.
41340 syncValue : function(){
41341 if(this.initialized){
41342 var bd = (this.doc.body || this.doc.documentElement);
41343 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41344 var html = bd.innerHTML;
41346 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41347 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41349 html = '<div style="'+m[0]+'">' + html + '</div>';
41352 html = this.cleanHtml(html);
41353 // fix up the special chars.. normaly like back quotes in word...
41354 // however we do not want to do this with chinese..
41355 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41356 var cc = b.charCodeAt();
41358 (cc >= 0x4E00 && cc < 0xA000 ) ||
41359 (cc >= 0x3400 && cc < 0x4E00 ) ||
41360 (cc >= 0xf900 && cc < 0xfb00 )
41366 if(this.owner.fireEvent('beforesync', this, html) !== false){
41367 this.el.dom.value = html;
41368 this.owner.fireEvent('sync', this, html);
41374 * Protected method that will not generally be called directly. Pushes the value of the textarea
41375 * into the iframe editor.
41377 pushValue : function(){
41378 if(this.initialized){
41379 var v = this.el.dom.value.trim();
41381 // if(v.length < 1){
41385 if(this.owner.fireEvent('beforepush', this, v) !== false){
41386 var d = (this.doc.body || this.doc.documentElement);
41388 this.cleanUpPaste();
41389 this.el.dom.value = d.innerHTML;
41390 this.owner.fireEvent('push', this, v);
41396 deferFocus : function(){
41397 this.focus.defer(10, this);
41401 focus : function(){
41402 if(this.win && !this.sourceEditMode){
41409 assignDocWin: function()
41411 var iframe = this.iframe;
41414 this.doc = iframe.contentWindow.document;
41415 this.win = iframe.contentWindow;
41417 // if (!Roo.get(this.frameId)) {
41420 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41421 // this.win = Roo.get(this.frameId).dom.contentWindow;
41423 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
41427 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41428 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
41433 initEditor : function(){
41434 //console.log("INIT EDITOR");
41435 this.assignDocWin();
41439 this.doc.designMode="on";
41441 this.doc.write(this.getDocMarkup());
41444 var dbody = (this.doc.body || this.doc.documentElement);
41445 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41446 // this copies styles from the containing element into thsi one..
41447 // not sure why we need all of this..
41448 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41450 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41451 //ss['background-attachment'] = 'fixed'; // w3c
41452 dbody.bgProperties = 'fixed'; // ie
41453 //Roo.DomHelper.applyStyles(dbody, ss);
41454 Roo.EventManager.on(this.doc, {
41455 //'mousedown': this.onEditorEvent,
41456 'mouseup': this.onEditorEvent,
41457 'dblclick': this.onEditorEvent,
41458 'click': this.onEditorEvent,
41459 'keyup': this.onEditorEvent,
41464 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41466 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41467 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41469 this.initialized = true;
41471 this.owner.fireEvent('initialize', this);
41476 onDestroy : function(){
41482 //for (var i =0; i < this.toolbars.length;i++) {
41483 // // fixme - ask toolbars for heights?
41484 // this.toolbars[i].onDestroy();
41487 //this.wrap.dom.innerHTML = '';
41488 //this.wrap.remove();
41493 onFirstFocus : function(){
41495 this.assignDocWin();
41498 this.activated = true;
41501 if(Roo.isGecko){ // prevent silly gecko errors
41503 var s = this.win.getSelection();
41504 if(!s.focusNode || s.focusNode.nodeType != 3){
41505 var r = s.getRangeAt(0);
41506 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41511 this.execCmd('useCSS', true);
41512 this.execCmd('styleWithCSS', false);
41515 this.owner.fireEvent('activate', this);
41519 adjustFont: function(btn){
41520 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41521 //if(Roo.isSafari){ // safari
41524 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41525 if(Roo.isSafari){ // safari
41526 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41527 v = (v < 10) ? 10 : v;
41528 v = (v > 48) ? 48 : v;
41529 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41534 v = Math.max(1, v+adjust);
41536 this.execCmd('FontSize', v );
41539 onEditorEvent : function(e){
41540 this.owner.fireEvent('editorevent', this, e);
41541 // this.updateToolbar();
41542 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41545 insertTag : function(tg)
41547 // could be a bit smarter... -> wrap the current selected tRoo..
41548 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41550 range = this.createRange(this.getSelection());
41551 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41552 wrappingNode.appendChild(range.extractContents());
41553 range.insertNode(wrappingNode);
41560 this.execCmd("formatblock", tg);
41564 insertText : function(txt)
41568 var range = this.createRange();
41569 range.deleteContents();
41570 //alert(Sender.getAttribute('label'));
41572 range.insertNode(this.doc.createTextNode(txt));
41578 * Executes a Midas editor command on the editor document and performs necessary focus and
41579 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41580 * @param {String} cmd The Midas command
41581 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41583 relayCmd : function(cmd, value){
41585 this.execCmd(cmd, value);
41586 this.owner.fireEvent('editorevent', this);
41587 //this.updateToolbar();
41588 this.owner.deferFocus();
41592 * Executes a Midas editor command directly on the editor document.
41593 * For visual commands, you should use {@link #relayCmd} instead.
41594 * <b>This should only be called after the editor is initialized.</b>
41595 * @param {String} cmd The Midas command
41596 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41598 execCmd : function(cmd, value){
41599 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41606 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41608 * @param {String} text | dom node..
41610 insertAtCursor : function(text)
41615 if(!this.activated){
41621 var r = this.doc.selection.createRange();
41632 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41636 // from jquery ui (MIT licenced)
41638 var win = this.win;
41640 if (win.getSelection && win.getSelection().getRangeAt) {
41641 range = win.getSelection().getRangeAt(0);
41642 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41643 range.insertNode(node);
41644 } else if (win.document.selection && win.document.selection.createRange) {
41645 // no firefox support
41646 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41647 win.document.selection.createRange().pasteHTML(txt);
41649 // no firefox support
41650 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41651 this.execCmd('InsertHTML', txt);
41660 mozKeyPress : function(e){
41662 var c = e.getCharCode(), cmd;
41665 c = String.fromCharCode(c).toLowerCase();
41679 this.cleanUpPaste.defer(100, this);
41687 e.preventDefault();
41695 fixKeys : function(){ // load time branching for fastest keydown performance
41697 return function(e){
41698 var k = e.getKey(), r;
41701 r = this.doc.selection.createRange();
41704 r.pasteHTML('    ');
41711 r = this.doc.selection.createRange();
41713 var target = r.parentElement();
41714 if(!target || target.tagName.toLowerCase() != 'li'){
41716 r.pasteHTML('<br />');
41722 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41723 this.cleanUpPaste.defer(100, this);
41729 }else if(Roo.isOpera){
41730 return function(e){
41731 var k = e.getKey();
41735 this.execCmd('InsertHTML','    ');
41738 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41739 this.cleanUpPaste.defer(100, this);
41744 }else if(Roo.isSafari){
41745 return function(e){
41746 var k = e.getKey();
41750 this.execCmd('InsertText','\t');
41754 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41755 this.cleanUpPaste.defer(100, this);
41763 getAllAncestors: function()
41765 var p = this.getSelectedNode();
41768 a.push(p); // push blank onto stack..
41769 p = this.getParentElement();
41773 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41777 a.push(this.doc.body);
41781 lastSelNode : false,
41784 getSelection : function()
41786 this.assignDocWin();
41787 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41790 getSelectedNode: function()
41792 // this may only work on Gecko!!!
41794 // should we cache this!!!!
41799 var range = this.createRange(this.getSelection()).cloneRange();
41802 var parent = range.parentElement();
41804 var testRange = range.duplicate();
41805 testRange.moveToElementText(parent);
41806 if (testRange.inRange(range)) {
41809 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41812 parent = parent.parentElement;
41817 // is ancestor a text element.
41818 var ac = range.commonAncestorContainer;
41819 if (ac.nodeType == 3) {
41820 ac = ac.parentNode;
41823 var ar = ac.childNodes;
41826 var other_nodes = [];
41827 var has_other_nodes = false;
41828 for (var i=0;i<ar.length;i++) {
41829 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41832 // fullly contained node.
41834 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41839 // probably selected..
41840 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41841 other_nodes.push(ar[i]);
41845 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41850 has_other_nodes = true;
41852 if (!nodes.length && other_nodes.length) {
41853 nodes= other_nodes;
41855 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41861 createRange: function(sel)
41863 // this has strange effects when using with
41864 // top toolbar - not sure if it's a great idea.
41865 //this.editor.contentWindow.focus();
41866 if (typeof sel != "undefined") {
41868 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41870 return this.doc.createRange();
41873 return this.doc.createRange();
41876 getParentElement: function()
41879 this.assignDocWin();
41880 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41882 var range = this.createRange(sel);
41885 var p = range.commonAncestorContainer;
41886 while (p.nodeType == 3) { // text node
41897 * Range intersection.. the hard stuff...
41901 * [ -- selected range --- ]
41905 * if end is before start or hits it. fail.
41906 * if start is after end or hits it fail.
41908 * if either hits (but other is outside. - then it's not
41914 // @see http://www.thismuchiknow.co.uk/?p=64.
41915 rangeIntersectsNode : function(range, node)
41917 var nodeRange = node.ownerDocument.createRange();
41919 nodeRange.selectNode(node);
41921 nodeRange.selectNodeContents(node);
41924 var rangeStartRange = range.cloneRange();
41925 rangeStartRange.collapse(true);
41927 var rangeEndRange = range.cloneRange();
41928 rangeEndRange.collapse(false);
41930 var nodeStartRange = nodeRange.cloneRange();
41931 nodeStartRange.collapse(true);
41933 var nodeEndRange = nodeRange.cloneRange();
41934 nodeEndRange.collapse(false);
41936 return rangeStartRange.compareBoundaryPoints(
41937 Range.START_TO_START, nodeEndRange) == -1 &&
41938 rangeEndRange.compareBoundaryPoints(
41939 Range.START_TO_START, nodeStartRange) == 1;
41943 rangeCompareNode : function(range, node)
41945 var nodeRange = node.ownerDocument.createRange();
41947 nodeRange.selectNode(node);
41949 nodeRange.selectNodeContents(node);
41953 range.collapse(true);
41955 nodeRange.collapse(true);
41957 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41958 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41960 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41962 var nodeIsBefore = ss == 1;
41963 var nodeIsAfter = ee == -1;
41965 if (nodeIsBefore && nodeIsAfter)
41967 if (!nodeIsBefore && nodeIsAfter)
41968 return 1; //right trailed.
41970 if (nodeIsBefore && !nodeIsAfter)
41971 return 2; // left trailed.
41976 // private? - in a new class?
41977 cleanUpPaste : function()
41979 // cleans up the whole document..
41980 Roo.log('cleanuppaste');
41982 this.cleanUpChildren(this.doc.body);
41983 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41984 if (clean != this.doc.body.innerHTML) {
41985 this.doc.body.innerHTML = clean;
41990 cleanWordChars : function(input) {// change the chars to hex code
41991 var he = Roo.HtmlEditorCore;
41993 var output = input;
41994 Roo.each(he.swapCodes, function(sw) {
41995 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41997 output = output.replace(swapper, sw[1]);
42004 cleanUpChildren : function (n)
42006 if (!n.childNodes.length) {
42009 for (var i = n.childNodes.length-1; i > -1 ; i--) {
42010 this.cleanUpChild(n.childNodes[i]);
42017 cleanUpChild : function (node)
42020 //console.log(node);
42021 if (node.nodeName == "#text") {
42022 // clean up silly Windows -- stuff?
42025 if (node.nodeName == "#comment") {
42026 node.parentNode.removeChild(node);
42027 // clean up silly Windows -- stuff?
42030 var lcname = node.tagName.toLowerCase();
42031 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
42032 // whitelist of tags..
42034 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
42036 node.parentNode.removeChild(node);
42041 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
42043 // remove <a name=....> as rendering on yahoo mailer is borked with this.
42044 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42046 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42047 // remove_keep_children = true;
42050 if (remove_keep_children) {
42051 this.cleanUpChildren(node);
42052 // inserts everything just before this node...
42053 while (node.childNodes.length) {
42054 var cn = node.childNodes[0];
42055 node.removeChild(cn);
42056 node.parentNode.insertBefore(cn, node);
42058 node.parentNode.removeChild(node);
42062 if (!node.attributes || !node.attributes.length) {
42063 this.cleanUpChildren(node);
42067 function cleanAttr(n,v)
42070 if (v.match(/^\./) || v.match(/^\//)) {
42073 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42076 if (v.match(/^#/)) {
42079 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42080 node.removeAttribute(n);
42084 var cwhite = this.cwhite;
42085 var cblack = this.cblack;
42087 function cleanStyle(n,v)
42089 if (v.match(/expression/)) { //XSS?? should we even bother..
42090 node.removeAttribute(n);
42094 var parts = v.split(/;/);
42097 Roo.each(parts, function(p) {
42098 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42102 var l = p.split(':').shift().replace(/\s+/g,'');
42103 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42105 if ( cwhite.length && cblack.indexOf(l) > -1) {
42106 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42107 //node.removeAttribute(n);
42111 // only allow 'c whitelisted system attributes'
42112 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42113 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42114 //node.removeAttribute(n);
42124 if (clean.length) {
42125 node.setAttribute(n, clean.join(';'));
42127 node.removeAttribute(n);
42133 for (var i = node.attributes.length-1; i > -1 ; i--) {
42134 var a = node.attributes[i];
42137 if (a.name.toLowerCase().substr(0,2)=='on') {
42138 node.removeAttribute(a.name);
42141 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42142 node.removeAttribute(a.name);
42145 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42146 cleanAttr(a.name,a.value); // fixme..
42149 if (a.name == 'style') {
42150 cleanStyle(a.name,a.value);
42153 /// clean up MS crap..
42154 // tecnically this should be a list of valid class'es..
42157 if (a.name == 'class') {
42158 if (a.value.match(/^Mso/)) {
42159 node.className = '';
42162 if (a.value.match(/body/)) {
42163 node.className = '';
42174 this.cleanUpChildren(node);
42179 * Clean up MS wordisms...
42181 cleanWord : function(node)
42184 var cleanWordChildren = function()
42186 if (!node.childNodes.length) {
42189 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42190 _t.cleanWord(node.childNodes[i]);
42196 this.cleanWord(this.doc.body);
42199 if (node.nodeName == "#text") {
42200 // clean up silly Windows -- stuff?
42203 if (node.nodeName == "#comment") {
42204 node.parentNode.removeChild(node);
42205 // clean up silly Windows -- stuff?
42209 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42210 node.parentNode.removeChild(node);
42214 // remove - but keep children..
42215 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42216 while (node.childNodes.length) {
42217 var cn = node.childNodes[0];
42218 node.removeChild(cn);
42219 node.parentNode.insertBefore(cn, node);
42221 node.parentNode.removeChild(node);
42222 cleanWordChildren();
42226 if (node.className.length) {
42228 var cn = node.className.split(/\W+/);
42230 Roo.each(cn, function(cls) {
42231 if (cls.match(/Mso[a-zA-Z]+/)) {
42236 node.className = cna.length ? cna.join(' ') : '';
42238 node.removeAttribute("class");
42242 if (node.hasAttribute("lang")) {
42243 node.removeAttribute("lang");
42246 if (node.hasAttribute("style")) {
42248 var styles = node.getAttribute("style").split(";");
42250 Roo.each(styles, function(s) {
42251 if (!s.match(/:/)) {
42254 var kv = s.split(":");
42255 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42258 // what ever is left... we allow.
42261 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42262 if (!nstyle.length) {
42263 node.removeAttribute('style');
42267 cleanWordChildren();
42271 domToHTML : function(currentElement, depth, nopadtext) {
42273 depth = depth || 0;
42274 nopadtext = nopadtext || false;
42276 if (!currentElement) {
42277 return this.domToHTML(this.doc.body);
42280 //Roo.log(currentElement);
42282 var allText = false;
42283 var nodeName = currentElement.nodeName;
42284 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42286 if (nodeName == '#text') {
42287 return currentElement.nodeValue;
42292 if (nodeName != 'BODY') {
42295 // Prints the node tagName, such as <A>, <IMG>, etc
42298 for(i = 0; i < currentElement.attributes.length;i++) {
42300 var aname = currentElement.attributes.item(i).name;
42301 if (!currentElement.attributes.item(i).value.length) {
42304 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42307 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42316 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42319 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42324 // Traverse the tree
42326 var currentElementChild = currentElement.childNodes.item(i);
42327 var allText = true;
42328 var innerHTML = '';
42330 while (currentElementChild) {
42331 // Formatting code (indent the tree so it looks nice on the screen)
42332 var nopad = nopadtext;
42333 if (lastnode == 'SPAN') {
42337 if (currentElementChild.nodeName == '#text') {
42338 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42339 if (!nopad && toadd.length > 80) {
42340 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42342 innerHTML += toadd;
42345 currentElementChild = currentElement.childNodes.item(i);
42351 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42353 // Recursively traverse the tree structure of the child node
42354 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42355 lastnode = currentElementChild.nodeName;
42357 currentElementChild=currentElement.childNodes.item(i);
42363 // The remaining code is mostly for formatting the tree
42364 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42369 ret+= "</"+tagName+">";
42375 applyBlacklists : function()
42377 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
42378 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
42382 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
42383 if (b.indexOf(tag) > -1) {
42386 this.white.push(tag);
42390 Roo.each(w, function(tag) {
42391 if (b.indexOf(tag) > -1) {
42394 if (this.white.indexOf(tag) > -1) {
42397 this.white.push(tag);
42402 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
42403 if (w.indexOf(tag) > -1) {
42406 this.black.push(tag);
42410 Roo.each(b, function(tag) {
42411 if (w.indexOf(tag) > -1) {
42414 if (this.black.indexOf(tag) > -1) {
42417 this.black.push(tag);
42422 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
42423 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
42427 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
42428 if (b.indexOf(tag) > -1) {
42431 this.cwhite.push(tag);
42435 Roo.each(w, function(tag) {
42436 if (b.indexOf(tag) > -1) {
42439 if (this.cwhite.indexOf(tag) > -1) {
42442 this.cwhite.push(tag);
42447 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
42448 if (w.indexOf(tag) > -1) {
42451 this.cblack.push(tag);
42455 Roo.each(b, function(tag) {
42456 if (w.indexOf(tag) > -1) {
42459 if (this.cblack.indexOf(tag) > -1) {
42462 this.cblack.push(tag);
42467 // hide stuff that is not compatible
42481 * @event specialkey
42485 * @cfg {String} fieldClass @hide
42488 * @cfg {String} focusClass @hide
42491 * @cfg {String} autoCreate @hide
42494 * @cfg {String} inputType @hide
42497 * @cfg {String} invalidClass @hide
42500 * @cfg {String} invalidText @hide
42503 * @cfg {String} msgFx @hide
42506 * @cfg {String} validateOnBlur @hide
42510 Roo.HtmlEditorCore.white = [
42511 'area', 'br', 'img', 'input', 'hr', 'wbr',
42513 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42514 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42515 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42516 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42517 'table', 'ul', 'xmp',
42519 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42522 'dir', 'menu', 'ol', 'ul', 'dl',
42528 Roo.HtmlEditorCore.black = [
42529 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42531 'base', 'basefont', 'bgsound', 'blink', 'body',
42532 'frame', 'frameset', 'head', 'html', 'ilayer',
42533 'iframe', 'layer', 'link', 'meta', 'object',
42534 'script', 'style' ,'title', 'xml' // clean later..
42536 Roo.HtmlEditorCore.clean = [
42537 'script', 'style', 'title', 'xml'
42539 Roo.HtmlEditorCore.remove = [
42544 Roo.HtmlEditorCore.ablack = [
42548 Roo.HtmlEditorCore.aclean = [
42549 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42553 Roo.HtmlEditorCore.pwhite= [
42554 'http', 'https', 'mailto'
42557 // white listed style attributes.
42558 Roo.HtmlEditorCore.cwhite= [
42559 // 'text-align', /// default is to allow most things..
42565 // black listed style attributes.
42566 Roo.HtmlEditorCore.cblack= [
42567 // 'font-size' -- this can be set by the project
42571 Roo.HtmlEditorCore.swapCodes =[
42582 //<script type="text/javascript">
42585 * Ext JS Library 1.1.1
42586 * Copyright(c) 2006-2007, Ext JS, LLC.
42592 Roo.form.HtmlEditor = function(config){
42596 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42598 if (!this.toolbars) {
42599 this.toolbars = [];
42601 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42607 * @class Roo.form.HtmlEditor
42608 * @extends Roo.form.Field
42609 * Provides a lightweight HTML Editor component.
42611 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42613 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42614 * supported by this editor.</b><br/><br/>
42615 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42616 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42618 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42620 * @cfg {Boolean} clearUp
42624 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42629 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42634 * @cfg {Number} height (in pixels)
42638 * @cfg {Number} width (in pixels)
42643 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42646 stylesheets: false,
42650 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
42655 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
42661 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
42666 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
42674 // private properties
42675 validationEvent : false,
42677 initialized : false,
42680 onFocus : Roo.emptyFn,
42682 hideMode:'offsets',
42684 defaultAutoCreate : { // modified by initCompnoent..
42686 style:"width:500px;height:300px;",
42687 autocomplete: "off"
42691 initComponent : function(){
42694 * @event initialize
42695 * Fires when the editor is fully initialized (including the iframe)
42696 * @param {HtmlEditor} this
42701 * Fires when the editor is first receives the focus. Any insertion must wait
42702 * until after this event.
42703 * @param {HtmlEditor} this
42707 * @event beforesync
42708 * Fires before the textarea is updated with content from the editor iframe. Return false
42709 * to cancel the sync.
42710 * @param {HtmlEditor} this
42711 * @param {String} html
42715 * @event beforepush
42716 * Fires before the iframe editor is updated with content from the textarea. Return false
42717 * to cancel the push.
42718 * @param {HtmlEditor} this
42719 * @param {String} html
42724 * Fires when the textarea is updated with content from the editor iframe.
42725 * @param {HtmlEditor} this
42726 * @param {String} html
42731 * Fires when the iframe editor is updated with content from the textarea.
42732 * @param {HtmlEditor} this
42733 * @param {String} html
42737 * @event editmodechange
42738 * Fires when the editor switches edit modes
42739 * @param {HtmlEditor} this
42740 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42742 editmodechange: true,
42744 * @event editorevent
42745 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42746 * @param {HtmlEditor} this
42750 * @event firstfocus
42751 * Fires when on first focus - needed by toolbars..
42752 * @param {HtmlEditor} this
42757 * Auto save the htmlEditor value as a file into Events
42758 * @param {HtmlEditor} this
42762 * @event savedpreview
42763 * preview the saved version of htmlEditor
42764 * @param {HtmlEditor} this
42768 this.defaultAutoCreate = {
42770 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42771 autocomplete: "off"
42776 * Protected method that will not generally be called directly. It
42777 * is called when the editor creates its toolbar. Override this method if you need to
42778 * add custom toolbar buttons.
42779 * @param {HtmlEditor} editor
42781 createToolbar : function(editor){
42782 Roo.log("create toolbars");
42783 if (!editor.toolbars || !editor.toolbars.length) {
42784 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42787 for (var i =0 ; i < editor.toolbars.length;i++) {
42788 editor.toolbars[i] = Roo.factory(
42789 typeof(editor.toolbars[i]) == 'string' ?
42790 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42791 Roo.form.HtmlEditor);
42792 editor.toolbars[i].init(editor);
42800 onRender : function(ct, position)
42803 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
42805 this.wrap = this.el.wrap({
42806 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
42809 this.editorcore.onRender(ct, position);
42811 if (this.resizable) {
42812 this.resizeEl = new Roo.Resizable(this.wrap, {
42816 minHeight : this.height,
42817 height: this.height,
42818 handles : this.resizable,
42821 resize : function(r, w, h) {
42822 _t.onResize(w,h); // -something
42828 this.createToolbar(this);
42832 this.setSize(this.wrap.getSize());
42834 if (this.resizeEl) {
42835 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
42836 // should trigger onReize..
42839 // if(this.autosave && this.w){
42840 // this.autoSaveFn = setInterval(this.autosave, 1000);
42845 onResize : function(w, h)
42847 //Roo.log('resize: ' +w + ',' + h );
42848 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
42853 if(typeof w == 'number'){
42854 var aw = w - this.wrap.getFrameWidth('lr');
42855 this.el.setWidth(this.adjustWidth('textarea', aw));
42858 if(typeof h == 'number'){
42860 for (var i =0; i < this.toolbars.length;i++) {
42861 // fixme - ask toolbars for heights?
42862 tbh += this.toolbars[i].tb.el.getHeight();
42863 if (this.toolbars[i].footer) {
42864 tbh += this.toolbars[i].footer.el.getHeight();
42871 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
42872 ah -= 5; // knock a few pixes off for look..
42873 this.el.setHeight(this.adjustWidth('textarea', ah));
42877 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
42878 this.editorcore.onResize(ew,eh);
42883 * Toggles the editor between standard and source edit mode.
42884 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42886 toggleSourceEdit : function(sourceEditMode)
42888 this.editorcore.toggleSourceEdit(sourceEditMode);
42890 if(this.editorcore.sourceEditMode){
42891 Roo.log('editor - showing textarea');
42894 // Roo.log(this.syncValue());
42895 this.editorcore.syncValue();
42896 this.el.removeClass('x-hidden');
42897 this.el.dom.removeAttribute('tabIndex');
42900 Roo.log('editor - hiding textarea');
42902 // Roo.log(this.pushValue());
42903 this.editorcore.pushValue();
42905 this.el.addClass('x-hidden');
42906 this.el.dom.setAttribute('tabIndex', -1);
42907 //this.deferFocus();
42910 this.setSize(this.wrap.getSize());
42911 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
42914 // private (for BoxComponent)
42915 adjustSize : Roo.BoxComponent.prototype.adjustSize,
42917 // private (for BoxComponent)
42918 getResizeEl : function(){
42922 // private (for BoxComponent)
42923 getPositionEl : function(){
42928 initEvents : function(){
42929 this.originalValue = this.getValue();
42933 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42936 markInvalid : Roo.emptyFn,
42938 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42941 clearInvalid : Roo.emptyFn,
42943 setValue : function(v){
42944 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
42945 this.editorcore.pushValue();
42950 deferFocus : function(){
42951 this.focus.defer(10, this);
42955 focus : function(){
42956 this.editorcore.focus();
42962 onDestroy : function(){
42968 for (var i =0; i < this.toolbars.length;i++) {
42969 // fixme - ask toolbars for heights?
42970 this.toolbars[i].onDestroy();
42973 this.wrap.dom.innerHTML = '';
42974 this.wrap.remove();
42979 onFirstFocus : function(){
42980 //Roo.log("onFirstFocus");
42981 this.editorcore.onFirstFocus();
42982 for (var i =0; i < this.toolbars.length;i++) {
42983 this.toolbars[i].onFirstFocus();
42989 syncValue : function()
42991 this.editorcore.syncValue();
42994 pushValue : function()
42996 this.editorcore.pushValue();
43000 // hide stuff that is not compatible
43014 * @event specialkey
43018 * @cfg {String} fieldClass @hide
43021 * @cfg {String} focusClass @hide
43024 * @cfg {String} autoCreate @hide
43027 * @cfg {String} inputType @hide
43030 * @cfg {String} invalidClass @hide
43033 * @cfg {String} invalidText @hide
43036 * @cfg {String} msgFx @hide
43039 * @cfg {String} validateOnBlur @hide
43043 // <script type="text/javascript">
43046 * Ext JS Library 1.1.1
43047 * Copyright(c) 2006-2007, Ext JS, LLC.
43053 * @class Roo.form.HtmlEditorToolbar1
43058 new Roo.form.HtmlEditor({
43061 new Roo.form.HtmlEditorToolbar1({
43062 disable : { fonts: 1 , format: 1, ..., ... , ...],
43068 * @cfg {Object} disable List of elements to disable..
43069 * @cfg {Array} btns List of additional buttons.
43073 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
43076 Roo.form.HtmlEditor.ToolbarStandard = function(config)
43079 Roo.apply(this, config);
43081 // default disabled, based on 'good practice'..
43082 this.disable = this.disable || {};
43083 Roo.applyIf(this.disable, {
43086 specialElements : true
43090 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43091 // dont call parent... till later.
43094 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
43101 editorcore : false,
43103 * @cfg {Object} disable List of toolbar elements to disable
43110 * @cfg {String} createLinkText The default text for the create link prompt
43112 createLinkText : 'Please enter the URL for the link:',
43114 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
43116 defaultLinkValue : 'http:/'+'/',
43120 * @cfg {Array} fontFamilies An array of available font families
43138 // "á" , ?? a acute?
43143 "°" // , // degrees
43145 // "é" , // e ecute
43146 // "ú" , // u ecute?
43149 specialElements : [
43151 text: "Insert Table",
43154 ihtml : '<table><tr><td>Cell</td></tr></table>'
43158 text: "Insert Image",
43161 ihtml : '<img src="about:blank"/>'
43170 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43171 "input:submit", "input:button", "select", "textarea", "label" ],
43174 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43176 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43184 * @cfg {String} defaultFont default font to use.
43186 defaultFont: 'tahoma',
43188 fontSelect : false,
43191 formatCombo : false,
43193 init : function(editor)
43195 this.editor = editor;
43196 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43197 var editorcore = this.editorcore;
43201 var fid = editorcore.frameId;
43203 function btn(id, toggle, handler){
43204 var xid = fid + '-'+ id ;
43208 cls : 'x-btn-icon x-edit-'+id,
43209 enableToggle:toggle !== false,
43210 scope: _t, // was editor...
43211 handler:handler||_t.relayBtnCmd,
43212 clickEvent:'mousedown',
43213 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43220 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43222 // stop form submits
43223 tb.el.on('click', function(e){
43224 e.preventDefault(); // what does this do?
43227 if(!this.disable.font) { // && !Roo.isSafari){
43228 /* why no safari for fonts
43229 editor.fontSelect = tb.el.createChild({
43232 cls:'x-font-select',
43233 html: this.createFontOptions()
43236 editor.fontSelect.on('change', function(){
43237 var font = editor.fontSelect.dom.value;
43238 editor.relayCmd('fontname', font);
43239 editor.deferFocus();
43243 editor.fontSelect.dom,
43249 if(!this.disable.formats){
43250 this.formatCombo = new Roo.form.ComboBox({
43251 store: new Roo.data.SimpleStore({
43254 data : this.formats // from states.js
43258 //autoCreate : {tag: "div", size: "20"},
43259 displayField:'tag',
43263 triggerAction: 'all',
43264 emptyText:'Add tag',
43265 selectOnFocus:true,
43268 'select': function(c, r, i) {
43269 editorcore.insertTag(r.get('tag'));
43275 tb.addField(this.formatCombo);
43279 if(!this.disable.format){
43286 if(!this.disable.fontSize){
43291 btn('increasefontsize', false, editorcore.adjustFont),
43292 btn('decreasefontsize', false, editorcore.adjustFont)
43297 if(!this.disable.colors){
43300 id:editorcore.frameId +'-forecolor',
43301 cls:'x-btn-icon x-edit-forecolor',
43302 clickEvent:'mousedown',
43303 tooltip: this.buttonTips['forecolor'] || undefined,
43305 menu : new Roo.menu.ColorMenu({
43306 allowReselect: true,
43307 focus: Roo.emptyFn,
43310 selectHandler: function(cp, color){
43311 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43312 editor.deferFocus();
43315 clickEvent:'mousedown'
43318 id:editorcore.frameId +'backcolor',
43319 cls:'x-btn-icon x-edit-backcolor',
43320 clickEvent:'mousedown',
43321 tooltip: this.buttonTips['backcolor'] || undefined,
43323 menu : new Roo.menu.ColorMenu({
43324 focus: Roo.emptyFn,
43327 allowReselect: true,
43328 selectHandler: function(cp, color){
43330 editorcore.execCmd('useCSS', false);
43331 editorcore.execCmd('hilitecolor', color);
43332 editorcore.execCmd('useCSS', true);
43333 editor.deferFocus();
43335 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43336 Roo.isSafari || Roo.isIE ? '#'+color : color);
43337 editor.deferFocus();
43341 clickEvent:'mousedown'
43346 // now add all the items...
43349 if(!this.disable.alignments){
43352 btn('justifyleft'),
43353 btn('justifycenter'),
43354 btn('justifyright')
43358 //if(!Roo.isSafari){
43359 if(!this.disable.links){
43362 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43366 if(!this.disable.lists){
43369 btn('insertorderedlist'),
43370 btn('insertunorderedlist')
43373 if(!this.disable.sourceEdit){
43376 btn('sourceedit', true, function(btn){
43378 this.toggleSourceEdit(btn.pressed);
43385 // special menu.. - needs to be tidied up..
43386 if (!this.disable.special) {
43389 cls: 'x-edit-none',
43395 for (var i =0; i < this.specialChars.length; i++) {
43396 smenu.menu.items.push({
43398 html: this.specialChars[i],
43399 handler: function(a,b) {
43400 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43401 //editor.insertAtCursor(a.html);
43415 if (!this.disable.cleanStyles) {
43417 cls: 'x-btn-icon x-btn-clear',
43423 for (var i =0; i < this.cleanStyles.length; i++) {
43424 cmenu.menu.items.push({
43425 actiontype : this.cleanStyles[i],
43426 html: 'Remove ' + this.cleanStyles[i],
43427 handler: function(a,b) {
43430 var c = Roo.get(editorcore.doc.body);
43431 c.select('[style]').each(function(s) {
43432 s.dom.style.removeProperty(a.actiontype);
43434 editorcore.syncValue();
43439 cmenu.menu.items.push({
43440 actiontype : 'word',
43441 html: 'Remove MS Word Formating',
43442 handler: function(a,b) {
43443 editorcore.cleanWord();
43444 editorcore.syncValue();
43449 cmenu.menu.items.push({
43450 actiontype : 'all',
43451 html: 'Remove All Styles',
43452 handler: function(a,b) {
43454 var c = Roo.get(editorcore.doc.body);
43455 c.select('[style]').each(function(s) {
43456 s.dom.removeAttribute('style');
43458 editorcore.syncValue();
43462 cmenu.menu.items.push({
43463 actiontype : 'word',
43464 html: 'Tidy HTML Source',
43465 handler: function(a,b) {
43466 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43467 editorcore.syncValue();
43476 if (!this.disable.specialElements) {
43479 cls: 'x-edit-none',
43484 for (var i =0; i < this.specialElements.length; i++) {
43485 semenu.menu.items.push(
43487 handler: function(a,b) {
43488 editor.insertAtCursor(this.ihtml);
43490 }, this.specialElements[i])
43502 for(var i =0; i< this.btns.length;i++) {
43503 var b = Roo.factory(this.btns[i],Roo.form);
43504 b.cls = 'x-edit-none';
43505 b.scope = editorcore;
43513 // disable everything...
43515 this.tb.items.each(function(item){
43516 if(item.id != editorcore.frameId+ '-sourceedit'){
43520 this.rendered = true;
43522 // the all the btns;
43523 editor.on('editorevent', this.updateToolbar, this);
43524 // other toolbars need to implement this..
43525 //editor.on('editmodechange', this.updateToolbar, this);
43529 relayBtnCmd : function(btn) {
43530 this.editorcore.relayCmd(btn.cmd);
43532 // private used internally
43533 createLink : function(){
43534 Roo.log("create link?");
43535 var url = prompt(this.createLinkText, this.defaultLinkValue);
43536 if(url && url != 'http:/'+'/'){
43537 this.editorcore.relayCmd('createlink', url);
43543 * Protected method that will not generally be called directly. It triggers
43544 * a toolbar update by reading the markup state of the current selection in the editor.
43546 updateToolbar: function(){
43548 if(!this.editorcore.activated){
43549 this.editor.onFirstFocus();
43553 var btns = this.tb.items.map,
43554 doc = this.editorcore.doc,
43555 frameId = this.editorcore.frameId;
43557 if(!this.disable.font && !Roo.isSafari){
43559 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43560 if(name != this.fontSelect.dom.value){
43561 this.fontSelect.dom.value = name;
43565 if(!this.disable.format){
43566 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43567 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43568 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43570 if(!this.disable.alignments){
43571 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43572 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43573 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43575 if(!Roo.isSafari && !this.disable.lists){
43576 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43577 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43580 var ans = this.editorcore.getAllAncestors();
43581 if (this.formatCombo) {
43584 var store = this.formatCombo.store;
43585 this.formatCombo.setValue("");
43586 for (var i =0; i < ans.length;i++) {
43587 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43589 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43597 // hides menus... - so this cant be on a menu...
43598 Roo.menu.MenuMgr.hideAll();
43600 //this.editorsyncValue();
43604 createFontOptions : function(){
43605 var buf = [], fs = this.fontFamilies, ff, lc;
43609 for(var i = 0, len = fs.length; i< len; i++){
43611 lc = ff.toLowerCase();
43613 '<option value="',lc,'" style="font-family:',ff,';"',
43614 (this.defaultFont == lc ? ' selected="true">' : '>'),
43619 return buf.join('');
43622 toggleSourceEdit : function(sourceEditMode){
43624 Roo.log("toolbar toogle");
43625 if(sourceEditMode === undefined){
43626 sourceEditMode = !this.sourceEditMode;
43628 this.sourceEditMode = sourceEditMode === true;
43629 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43630 // just toggle the button?
43631 if(btn.pressed !== this.sourceEditMode){
43632 btn.toggle(this.sourceEditMode);
43636 if(sourceEditMode){
43637 Roo.log("disabling buttons");
43638 this.tb.items.each(function(item){
43639 if(item.cmd != 'sourceedit'){
43645 Roo.log("enabling buttons");
43646 if(this.editorcore.initialized){
43647 this.tb.items.each(function(item){
43653 Roo.log("calling toggole on editor");
43654 // tell the editor that it's been pressed..
43655 this.editor.toggleSourceEdit(sourceEditMode);
43659 * Object collection of toolbar tooltips for the buttons in the editor. The key
43660 * is the command id associated with that button and the value is a valid QuickTips object.
43665 title: 'Bold (Ctrl+B)',
43666 text: 'Make the selected text bold.',
43667 cls: 'x-html-editor-tip'
43670 title: 'Italic (Ctrl+I)',
43671 text: 'Make the selected text italic.',
43672 cls: 'x-html-editor-tip'
43680 title: 'Bold (Ctrl+B)',
43681 text: 'Make the selected text bold.',
43682 cls: 'x-html-editor-tip'
43685 title: 'Italic (Ctrl+I)',
43686 text: 'Make the selected text italic.',
43687 cls: 'x-html-editor-tip'
43690 title: 'Underline (Ctrl+U)',
43691 text: 'Underline the selected text.',
43692 cls: 'x-html-editor-tip'
43694 increasefontsize : {
43695 title: 'Grow Text',
43696 text: 'Increase the font size.',
43697 cls: 'x-html-editor-tip'
43699 decreasefontsize : {
43700 title: 'Shrink Text',
43701 text: 'Decrease the font size.',
43702 cls: 'x-html-editor-tip'
43705 title: 'Text Highlight Color',
43706 text: 'Change the background color of the selected text.',
43707 cls: 'x-html-editor-tip'
43710 title: 'Font Color',
43711 text: 'Change the color of the selected text.',
43712 cls: 'x-html-editor-tip'
43715 title: 'Align Text Left',
43716 text: 'Align text to the left.',
43717 cls: 'x-html-editor-tip'
43720 title: 'Center Text',
43721 text: 'Center text in the editor.',
43722 cls: 'x-html-editor-tip'
43725 title: 'Align Text Right',
43726 text: 'Align text to the right.',
43727 cls: 'x-html-editor-tip'
43729 insertunorderedlist : {
43730 title: 'Bullet List',
43731 text: 'Start a bulleted list.',
43732 cls: 'x-html-editor-tip'
43734 insertorderedlist : {
43735 title: 'Numbered List',
43736 text: 'Start a numbered list.',
43737 cls: 'x-html-editor-tip'
43740 title: 'Hyperlink',
43741 text: 'Make the selected text a hyperlink.',
43742 cls: 'x-html-editor-tip'
43745 title: 'Source Edit',
43746 text: 'Switch to source editing mode.',
43747 cls: 'x-html-editor-tip'
43751 onDestroy : function(){
43754 this.tb.items.each(function(item){
43756 item.menu.removeAll();
43758 item.menu.el.destroy();
43766 onFirstFocus: function() {
43767 this.tb.items.each(function(item){
43776 // <script type="text/javascript">
43779 * Ext JS Library 1.1.1
43780 * Copyright(c) 2006-2007, Ext JS, LLC.
43787 * @class Roo.form.HtmlEditor.ToolbarContext
43792 new Roo.form.HtmlEditor({
43795 { xtype: 'ToolbarStandard', styles : {} }
43796 { xtype: 'ToolbarContext', disable : {} }
43802 * @config : {Object} disable List of elements to disable.. (not done yet.)
43803 * @config : {Object} styles Map of styles available.
43807 Roo.form.HtmlEditor.ToolbarContext = function(config)
43810 Roo.apply(this, config);
43811 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43812 // dont call parent... till later.
43813 this.styles = this.styles || {};
43818 Roo.form.HtmlEditor.ToolbarContext.types = {
43830 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
43896 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
43901 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
43911 style : 'fontFamily',
43912 displayField: 'display',
43913 optname : 'font-family',
43962 // should we really allow this??
43963 // should this just be
43974 style : 'fontFamily',
43975 displayField: 'display',
43976 optname : 'font-family',
43983 style : 'fontFamily',
43984 displayField: 'display',
43985 optname : 'font-family',
43992 style : 'fontFamily',
43993 displayField: 'display',
43994 optname : 'font-family',
44005 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
44006 Roo.form.HtmlEditor.ToolbarContext.stores = false;
44008 Roo.form.HtmlEditor.ToolbarContext.options = {
44010 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
44011 [ 'Courier New', 'Courier New'],
44012 [ 'Tahoma', 'Tahoma'],
44013 [ 'Times New Roman,serif', 'Times'],
44014 [ 'Verdana','Verdana' ]
44018 // fixme - these need to be configurable..
44021 Roo.form.HtmlEditor.ToolbarContext.types
44024 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
44031 editorcore : false,
44033 * @cfg {Object} disable List of toolbar elements to disable
44038 * @cfg {Object} styles List of styles
44039 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
44041 * These must be defined in the page, so they get rendered correctly..
44052 init : function(editor)
44054 this.editor = editor;
44055 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44056 var editorcore = this.editorcore;
44058 var fid = editorcore.frameId;
44060 function btn(id, toggle, handler){
44061 var xid = fid + '-'+ id ;
44065 cls : 'x-btn-icon x-edit-'+id,
44066 enableToggle:toggle !== false,
44067 scope: editorcore, // was editor...
44068 handler:handler||editorcore.relayBtnCmd,
44069 clickEvent:'mousedown',
44070 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44074 // create a new element.
44075 var wdiv = editor.wrap.createChild({
44077 }, editor.wrap.dom.firstChild.nextSibling, true);
44079 // can we do this more than once??
44081 // stop form submits
44084 // disable everything...
44085 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44086 this.toolbars = {};
44088 for (var i in ty) {
44090 this.toolbars[i] = this.buildToolbar(ty[i],i);
44092 this.tb = this.toolbars.BODY;
44094 this.buildFooter();
44095 this.footer.show();
44096 editor.on('hide', function( ) { this.footer.hide() }, this);
44097 editor.on('show', function( ) { this.footer.show() }, this);
44100 this.rendered = true;
44102 // the all the btns;
44103 editor.on('editorevent', this.updateToolbar, this);
44104 // other toolbars need to implement this..
44105 //editor.on('editmodechange', this.updateToolbar, this);
44111 * Protected method that will not generally be called directly. It triggers
44112 * a toolbar update by reading the markup state of the current selection in the editor.
44114 updateToolbar: function(editor,ev,sel){
44117 // capture mouse up - this is handy for selecting images..
44118 // perhaps should go somewhere else...
44119 if(!this.editorcore.activated){
44120 this.editor.onFirstFocus();
44124 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
44125 // selectNode - might want to handle IE?
44127 (ev.type == 'mouseup' || ev.type == 'click' ) &&
44128 ev.target && ev.target.tagName == 'IMG') {
44129 // they have click on an image...
44130 // let's see if we can change the selection...
44133 var nodeRange = sel.ownerDocument.createRange();
44135 nodeRange.selectNode(sel);
44137 nodeRange.selectNodeContents(sel);
44139 //nodeRange.collapse(true);
44140 var s = this.editorcore.win.getSelection();
44141 s.removeAllRanges();
44142 s.addRange(nodeRange);
44146 var updateFooter = sel ? false : true;
44149 var ans = this.editorcore.getAllAncestors();
44152 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44155 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
44156 sel = sel ? sel : this.editorcore.doc.body;
44157 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44160 // pick a menu that exists..
44161 var tn = sel.tagName.toUpperCase();
44162 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44164 tn = sel.tagName.toUpperCase();
44166 var lastSel = this.tb.selectedNode
44168 this.tb.selectedNode = sel;
44170 // if current menu does not match..
44171 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
44174 ///console.log("show: " + tn);
44175 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44178 this.tb.items.first().el.innerHTML = tn + ': ';
44181 // update attributes
44182 if (this.tb.fields) {
44183 this.tb.fields.each(function(e) {
44185 e.setValue(sel.style[e.stylename]);
44188 e.setValue(sel.getAttribute(e.attrname));
44192 var hasStyles = false;
44193 for(var i in this.styles) {
44200 var st = this.tb.fields.item(0);
44202 st.store.removeAll();
44205 var cn = sel.className.split(/\s+/);
44208 if (this.styles['*']) {
44210 Roo.each(this.styles['*'], function(v) {
44211 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44214 if (this.styles[tn]) {
44215 Roo.each(this.styles[tn], function(v) {
44216 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44220 st.store.loadData(avs);
44224 // flag our selected Node.
44225 this.tb.selectedNode = sel;
44228 Roo.menu.MenuMgr.hideAll();
44232 if (!updateFooter) {
44233 //this.footDisp.dom.innerHTML = '';
44236 // update the footer
44240 this.footerEls = ans.reverse();
44241 Roo.each(this.footerEls, function(a,i) {
44242 if (!a) { return; }
44243 html += html.length ? ' > ' : '';
44245 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44250 var sz = this.footDisp.up('td').getSize();
44251 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44252 this.footDisp.dom.style.marginLeft = '5px';
44254 this.footDisp.dom.style.overflow = 'hidden';
44256 this.footDisp.dom.innerHTML = html;
44258 //this.editorsyncValue();
44265 onDestroy : function(){
44268 this.tb.items.each(function(item){
44270 item.menu.removeAll();
44272 item.menu.el.destroy();
44280 onFirstFocus: function() {
44281 // need to do this for all the toolbars..
44282 this.tb.items.each(function(item){
44286 buildToolbar: function(tlist, nm)
44288 var editor = this.editor;
44289 var editorcore = this.editorcore;
44290 // create a new element.
44291 var wdiv = editor.wrap.createChild({
44293 }, editor.wrap.dom.firstChild.nextSibling, true);
44296 var tb = new Roo.Toolbar(wdiv);
44299 tb.add(nm+ ": ");
44302 for(var i in this.styles) {
44307 if (styles && styles.length) {
44309 // this needs a multi-select checkbox...
44310 tb.addField( new Roo.form.ComboBox({
44311 store: new Roo.data.SimpleStore({
44313 fields: ['val', 'selected'],
44316 name : '-roo-edit-className',
44317 attrname : 'className',
44318 displayField: 'val',
44322 triggerAction: 'all',
44323 emptyText:'Select Style',
44324 selectOnFocus:true,
44327 'select': function(c, r, i) {
44328 // initial support only for on class per el..
44329 tb.selectedNode.className = r ? r.get('val') : '';
44330 editorcore.syncValue();
44337 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44338 var tbops = tbc.options;
44340 for (var i in tlist) {
44342 var item = tlist[i];
44343 tb.add(item.title + ": ");
44346 //optname == used so you can configure the options available..
44347 var opts = item.opts ? item.opts : false;
44348 if (item.optname) {
44349 opts = tbops[item.optname];
44354 // opts == pulldown..
44355 tb.addField( new Roo.form.ComboBox({
44356 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44358 fields: ['val', 'display'],
44361 name : '-roo-edit-' + i,
44363 stylename : item.style ? item.style : false,
44364 displayField: item.displayField ? item.displayField : 'val',
44365 valueField : 'val',
44367 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44369 triggerAction: 'all',
44370 emptyText:'Select',
44371 selectOnFocus:true,
44372 width: item.width ? item.width : 130,
44374 'select': function(c, r, i) {
44376 tb.selectedNode.style[c.stylename] = r.get('val');
44379 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44388 tb.addField( new Roo.form.TextField({
44391 //allowBlank:false,
44396 tb.addField( new Roo.form.TextField({
44397 name: '-roo-edit-' + i,
44404 'change' : function(f, nv, ov) {
44405 tb.selectedNode.setAttribute(f.attrname, nv);
44414 text: 'Remove Tag',
44417 click : function ()
44420 // undo does not work.
44422 var sn = tb.selectedNode;
44424 var pn = sn.parentNode;
44426 var stn = sn.childNodes[0];
44427 var en = sn.childNodes[sn.childNodes.length - 1 ];
44428 while (sn.childNodes.length) {
44429 var node = sn.childNodes[0];
44430 sn.removeChild(node);
44432 pn.insertBefore(node, sn);
44435 pn.removeChild(sn);
44436 var range = editorcore.createRange();
44438 range.setStart(stn,0);
44439 range.setEnd(en,0); //????
44440 //range.selectNode(sel);
44443 var selection = editorcore.getSelection();
44444 selection.removeAllRanges();
44445 selection.addRange(range);
44449 //_this.updateToolbar(null, null, pn);
44450 _this.updateToolbar(null, null, null);
44451 _this.footDisp.dom.innerHTML = '';
44461 tb.el.on('click', function(e){
44462 e.preventDefault(); // what does this do?
44464 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44467 // dont need to disable them... as they will get hidden
44472 buildFooter : function()
44475 var fel = this.editor.wrap.createChild();
44476 this.footer = new Roo.Toolbar(fel);
44477 // toolbar has scrolly on left / right?
44478 var footDisp= new Roo.Toolbar.Fill();
44484 handler : function() {
44485 _t.footDisp.scrollTo('left',0,true)
44489 this.footer.add( footDisp );
44494 handler : function() {
44496 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44500 var fel = Roo.get(footDisp.el);
44501 fel.addClass('x-editor-context');
44502 this.footDispWrap = fel;
44503 this.footDispWrap.overflow = 'hidden';
44505 this.footDisp = fel.createChild();
44506 this.footDispWrap.on('click', this.onContextClick, this)
44510 onContextClick : function (ev,dom)
44512 ev.preventDefault();
44513 var cn = dom.className;
44515 if (!cn.match(/x-ed-loc-/)) {
44518 var n = cn.split('-').pop();
44519 var ans = this.footerEls;
44523 var range = this.editorcore.createRange();
44525 range.selectNodeContents(sel);
44526 //range.selectNode(sel);
44529 var selection = this.editorcore.getSelection();
44530 selection.removeAllRanges();
44531 selection.addRange(range);
44535 this.updateToolbar(null, null, sel);
44552 * Ext JS Library 1.1.1
44553 * Copyright(c) 2006-2007, Ext JS, LLC.
44555 * Originally Released Under LGPL - original licence link has changed is not relivant.
44558 * <script type="text/javascript">
44562 * @class Roo.form.BasicForm
44563 * @extends Roo.util.Observable
44564 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44566 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44567 * @param {Object} config Configuration options
44569 Roo.form.BasicForm = function(el, config){
44570 this.allItems = [];
44571 this.childForms = [];
44572 Roo.apply(this, config);
44574 * The Roo.form.Field items in this form.
44575 * @type MixedCollection
44579 this.items = new Roo.util.MixedCollection(false, function(o){
44580 return o.id || (o.id = Roo.id());
44584 * @event beforeaction
44585 * Fires before any action is performed. Return false to cancel the action.
44586 * @param {Form} this
44587 * @param {Action} action The action to be performed
44589 beforeaction: true,
44591 * @event actionfailed
44592 * Fires when an action fails.
44593 * @param {Form} this
44594 * @param {Action} action The action that failed
44596 actionfailed : true,
44598 * @event actioncomplete
44599 * Fires when an action is completed.
44600 * @param {Form} this
44601 * @param {Action} action The action that completed
44603 actioncomplete : true
44608 Roo.form.BasicForm.superclass.constructor.call(this);
44611 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44613 * @cfg {String} method
44614 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
44617 * @cfg {DataReader} reader
44618 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
44619 * This is optional as there is built-in support for processing JSON.
44622 * @cfg {DataReader} errorReader
44623 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
44624 * This is completely optional as there is built-in support for processing JSON.
44627 * @cfg {String} url
44628 * The URL to use for form actions if one isn't supplied in the action options.
44631 * @cfg {Boolean} fileUpload
44632 * Set to true if this form is a file upload.
44636 * @cfg {Object} baseParams
44637 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
44642 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
44647 activeAction : null,
44650 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
44651 * or setValues() data instead of when the form was first created.
44653 trackResetOnLoad : false,
44657 * childForms - used for multi-tab forms
44660 childForms : false,
44663 * allItems - full list of fields.
44669 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
44670 * element by passing it or its id or mask the form itself by passing in true.
44673 waitMsgTarget : false,
44676 initEl : function(el){
44677 this.el = Roo.get(el);
44678 this.id = this.el.id || Roo.id();
44679 this.el.on('submit', this.onSubmit, this);
44680 this.el.addClass('x-form');
44684 onSubmit : function(e){
44689 * Returns true if client-side validation on the form is successful.
44692 isValid : function(){
44694 this.items.each(function(f){
44703 * Returns true if any fields in this form have changed since their original load.
44706 isDirty : function(){
44708 this.items.each(function(f){
44718 * Performs a predefined action (submit or load) or custom actions you define on this form.
44719 * @param {String} actionName The name of the action type
44720 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
44721 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
44722 * accept other config options):
44724 Property Type Description
44725 ---------------- --------------- ----------------------------------------------------------------------------------
44726 url String The url for the action (defaults to the form's url)
44727 method String The form method to use (defaults to the form's method, or POST if not defined)
44728 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
44729 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
44730 validate the form on the client (defaults to false)
44732 * @return {BasicForm} this
44734 doAction : function(action, options){
44735 if(typeof action == 'string'){
44736 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
44738 if(this.fireEvent('beforeaction', this, action) !== false){
44739 this.beforeAction(action);
44740 action.run.defer(100, action);
44746 * Shortcut to do a submit action.
44747 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44748 * @return {BasicForm} this
44750 submit : function(options){
44751 this.doAction('submit', options);
44756 * Shortcut to do a load action.
44757 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44758 * @return {BasicForm} this
44760 load : function(options){
44761 this.doAction('load', options);
44766 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
44767 * @param {Record} record The record to edit
44768 * @return {BasicForm} this
44770 updateRecord : function(record){
44771 record.beginEdit();
44772 var fs = record.fields;
44773 fs.each(function(f){
44774 var field = this.findField(f.name);
44776 record.set(f.name, field.getValue());
44784 * Loads an Roo.data.Record into this form.
44785 * @param {Record} record The record to load
44786 * @return {BasicForm} this
44788 loadRecord : function(record){
44789 this.setValues(record.data);
44794 beforeAction : function(action){
44795 var o = action.options;
44798 if(this.waitMsgTarget === true){
44799 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
44800 }else if(this.waitMsgTarget){
44801 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
44802 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
44804 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
44810 afterAction : function(action, success){
44811 this.activeAction = null;
44812 var o = action.options;
44814 if(this.waitMsgTarget === true){
44816 }else if(this.waitMsgTarget){
44817 this.waitMsgTarget.unmask();
44819 Roo.MessageBox.updateProgress(1);
44820 Roo.MessageBox.hide();
44827 Roo.callback(o.success, o.scope, [this, action]);
44828 this.fireEvent('actioncomplete', this, action);
44832 // failure condition..
44833 // we have a scenario where updates need confirming.
44834 // eg. if a locking scenario exists..
44835 // we look for { errors : { needs_confirm : true }} in the response.
44837 (typeof(action.result) != 'undefined') &&
44838 (typeof(action.result.errors) != 'undefined') &&
44839 (typeof(action.result.errors.needs_confirm) != 'undefined')
44842 Roo.MessageBox.confirm(
44843 "Change requires confirmation",
44844 action.result.errorMsg,
44849 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
44859 Roo.callback(o.failure, o.scope, [this, action]);
44860 // show an error message if no failed handler is set..
44861 if (!this.hasListener('actionfailed')) {
44862 Roo.MessageBox.alert("Error",
44863 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
44864 action.result.errorMsg :
44865 "Saving Failed, please check your entries or try again"
44869 this.fireEvent('actionfailed', this, action);
44875 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
44876 * @param {String} id The value to search for
44879 findField : function(id){
44880 var field = this.items.get(id);
44882 this.items.each(function(f){
44883 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
44889 return field || null;
44893 * Add a secondary form to this one,
44894 * Used to provide tabbed forms. One form is primary, with hidden values
44895 * which mirror the elements from the other forms.
44897 * @param {Roo.form.Form} form to add.
44900 addForm : function(form)
44903 if (this.childForms.indexOf(form) > -1) {
44907 this.childForms.push(form);
44909 Roo.each(form.allItems, function (fe) {
44911 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
44912 if (this.findField(n)) { // already added..
44915 var add = new Roo.form.Hidden({
44918 add.render(this.el);
44925 * Mark fields in this form invalid in bulk.
44926 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
44927 * @return {BasicForm} this
44929 markInvalid : function(errors){
44930 if(errors instanceof Array){
44931 for(var i = 0, len = errors.length; i < len; i++){
44932 var fieldError = errors[i];
44933 var f = this.findField(fieldError.id);
44935 f.markInvalid(fieldError.msg);
44941 if(typeof errors[id] != 'function' && (field = this.findField(id))){
44942 field.markInvalid(errors[id]);
44946 Roo.each(this.childForms || [], function (f) {
44947 f.markInvalid(errors);
44954 * Set values for fields in this form in bulk.
44955 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
44956 * @return {BasicForm} this
44958 setValues : function(values){
44959 if(values instanceof Array){ // array of objects
44960 for(var i = 0, len = values.length; i < len; i++){
44962 var f = this.findField(v.id);
44964 f.setValue(v.value);
44965 if(this.trackResetOnLoad){
44966 f.originalValue = f.getValue();
44970 }else{ // object hash
44973 if(typeof values[id] != 'function' && (field = this.findField(id))){
44975 if (field.setFromData &&
44976 field.valueField &&
44977 field.displayField &&
44978 // combos' with local stores can
44979 // be queried via setValue()
44980 // to set their value..
44981 (field.store && !field.store.isLocal)
44985 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44986 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44987 field.setFromData(sd);
44990 field.setValue(values[id]);
44994 if(this.trackResetOnLoad){
44995 field.originalValue = field.getValue();
45001 Roo.each(this.childForms || [], function (f) {
45002 f.setValues(values);
45009 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
45010 * they are returned as an array.
45011 * @param {Boolean} asString
45014 getValues : function(asString){
45015 if (this.childForms) {
45016 // copy values from the child forms
45017 Roo.each(this.childForms, function (f) {
45018 this.setValues(f.getValues());
45024 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
45025 if(asString === true){
45028 return Roo.urlDecode(fs);
45032 * Returns the fields in this form as an object with key/value pairs.
45033 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
45036 getFieldValues : function(with_hidden)
45038 if (this.childForms) {
45039 // copy values from the child forms
45040 // should this call getFieldValues - probably not as we do not currently copy
45041 // hidden fields when we generate..
45042 Roo.each(this.childForms, function (f) {
45043 this.setValues(f.getValues());
45048 this.items.each(function(f){
45049 if (!f.getName()) {
45052 var v = f.getValue();
45053 if (f.inputType =='radio') {
45054 if (typeof(ret[f.getName()]) == 'undefined') {
45055 ret[f.getName()] = ''; // empty..
45058 if (!f.el.dom.checked) {
45062 v = f.el.dom.value;
45066 // not sure if this supported any more..
45067 if ((typeof(v) == 'object') && f.getRawValue) {
45068 v = f.getRawValue() ; // dates..
45070 // combo boxes where name != hiddenName...
45071 if (f.name != f.getName()) {
45072 ret[f.name] = f.getRawValue();
45074 ret[f.getName()] = v;
45081 * Clears all invalid messages in this form.
45082 * @return {BasicForm} this
45084 clearInvalid : function(){
45085 this.items.each(function(f){
45089 Roo.each(this.childForms || [], function (f) {
45098 * Resets this form.
45099 * @return {BasicForm} this
45101 reset : function(){
45102 this.items.each(function(f){
45106 Roo.each(this.childForms || [], function (f) {
45115 * Add Roo.form components to this form.
45116 * @param {Field} field1
45117 * @param {Field} field2 (optional)
45118 * @param {Field} etc (optional)
45119 * @return {BasicForm} this
45122 this.items.addAll(Array.prototype.slice.call(arguments, 0));
45128 * Removes a field from the items collection (does NOT remove its markup).
45129 * @param {Field} field
45130 * @return {BasicForm} this
45132 remove : function(field){
45133 this.items.remove(field);
45138 * Looks at the fields in this form, checks them for an id attribute,
45139 * and calls applyTo on the existing dom element with that id.
45140 * @return {BasicForm} this
45142 render : function(){
45143 this.items.each(function(f){
45144 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
45152 * Calls {@link Ext#apply} for all fields in this form with the passed object.
45153 * @param {Object} values
45154 * @return {BasicForm} this
45156 applyToFields : function(o){
45157 this.items.each(function(f){
45164 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45165 * @param {Object} values
45166 * @return {BasicForm} this
45168 applyIfToFields : function(o){
45169 this.items.each(function(f){
45177 Roo.BasicForm = Roo.form.BasicForm;/*
45179 * Ext JS Library 1.1.1
45180 * Copyright(c) 2006-2007, Ext JS, LLC.
45182 * Originally Released Under LGPL - original licence link has changed is not relivant.
45185 * <script type="text/javascript">
45189 * @class Roo.form.Form
45190 * @extends Roo.form.BasicForm
45191 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45193 * @param {Object} config Configuration options
45195 Roo.form.Form = function(config){
45197 if (config.items) {
45198 xitems = config.items;
45199 delete config.items;
45203 Roo.form.Form.superclass.constructor.call(this, null, config);
45204 this.url = this.url || this.action;
45206 this.root = new Roo.form.Layout(Roo.applyIf({
45210 this.active = this.root;
45212 * Array of all the buttons that have been added to this form via {@link addButton}
45216 this.allItems = [];
45219 * @event clientvalidation
45220 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45221 * @param {Form} this
45222 * @param {Boolean} valid true if the form has passed client-side validation
45224 clientvalidation: true,
45227 * Fires when the form is rendered
45228 * @param {Roo.form.Form} form
45233 if (this.progressUrl) {
45234 // push a hidden field onto the list of fields..
45238 name : 'UPLOAD_IDENTIFIER'
45243 Roo.each(xitems, this.addxtype, this);
45249 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45251 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45254 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45257 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45259 buttonAlign:'center',
45262 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45267 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45268 * This property cascades to child containers if not set.
45273 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45274 * fires a looping event with that state. This is required to bind buttons to the valid
45275 * state using the config value formBind:true on the button.
45277 monitorValid : false,
45280 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45285 * @cfg {String} progressUrl - Url to return progress data
45288 progressUrl : false,
45291 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45292 * fields are added and the column is closed. If no fields are passed the column remains open
45293 * until end() is called.
45294 * @param {Object} config The config to pass to the column
45295 * @param {Field} field1 (optional)
45296 * @param {Field} field2 (optional)
45297 * @param {Field} etc (optional)
45298 * @return Column The column container object
45300 column : function(c){
45301 var col = new Roo.form.Column(c);
45303 if(arguments.length > 1){ // duplicate code required because of Opera
45304 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45311 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45312 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45313 * until end() is called.
45314 * @param {Object} config The config to pass to the fieldset
45315 * @param {Field} field1 (optional)
45316 * @param {Field} field2 (optional)
45317 * @param {Field} etc (optional)
45318 * @return FieldSet The fieldset container object
45320 fieldset : function(c){
45321 var fs = new Roo.form.FieldSet(c);
45323 if(arguments.length > 1){ // duplicate code required because of Opera
45324 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45331 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45332 * fields are added and the container is closed. If no fields are passed the container remains open
45333 * until end() is called.
45334 * @param {Object} config The config to pass to the Layout
45335 * @param {Field} field1 (optional)
45336 * @param {Field} field2 (optional)
45337 * @param {Field} etc (optional)
45338 * @return Layout The container object
45340 container : function(c){
45341 var l = new Roo.form.Layout(c);
45343 if(arguments.length > 1){ // duplicate code required because of Opera
45344 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45351 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45352 * @param {Object} container A Roo.form.Layout or subclass of Layout
45353 * @return {Form} this
45355 start : function(c){
45356 // cascade label info
45357 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45358 this.active.stack.push(c);
45359 c.ownerCt = this.active;
45365 * Closes the current open container
45366 * @return {Form} this
45369 if(this.active == this.root){
45372 this.active = this.active.ownerCt;
45377 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45378 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45379 * as the label of the field.
45380 * @param {Field} field1
45381 * @param {Field} field2 (optional)
45382 * @param {Field} etc. (optional)
45383 * @return {Form} this
45386 this.active.stack.push.apply(this.active.stack, arguments);
45387 this.allItems.push.apply(this.allItems,arguments);
45389 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45390 if(a[i].isFormField){
45395 Roo.form.Form.superclass.add.apply(this, r);
45405 * Find any element that has been added to a form, using it's ID or name
45406 * This can include framesets, columns etc. along with regular fields..
45407 * @param {String} id - id or name to find.
45409 * @return {Element} e - or false if nothing found.
45411 findbyId : function(id)
45417 Roo.each(this.allItems, function(f){
45418 if (f.id == id || f.name == id ){
45429 * Render this form into the passed container. This should only be called once!
45430 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45431 * @return {Form} this
45433 render : function(ct)
45439 var o = this.autoCreate || {
45441 method : this.method || 'POST',
45442 id : this.id || Roo.id()
45444 this.initEl(ct.createChild(o));
45446 this.root.render(this.el);
45450 this.items.each(function(f){
45451 f.render('x-form-el-'+f.id);
45454 if(this.buttons.length > 0){
45455 // tables are required to maintain order and for correct IE layout
45456 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45457 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45458 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45460 var tr = tb.getElementsByTagName('tr')[0];
45461 for(var i = 0, len = this.buttons.length; i < len; i++) {
45462 var b = this.buttons[i];
45463 var td = document.createElement('td');
45464 td.className = 'x-form-btn-td';
45465 b.render(tr.appendChild(td));
45468 if(this.monitorValid){ // initialize after render
45469 this.startMonitoring();
45471 this.fireEvent('rendered', this);
45476 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45477 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45478 * object or a valid Roo.DomHelper element config
45479 * @param {Function} handler The function called when the button is clicked
45480 * @param {Object} scope (optional) The scope of the handler function
45481 * @return {Roo.Button}
45483 addButton : function(config, handler, scope){
45487 minWidth: this.minButtonWidth,
45490 if(typeof config == "string"){
45493 Roo.apply(bc, config);
45495 var btn = new Roo.Button(null, bc);
45496 this.buttons.push(btn);
45501 * Adds a series of form elements (using the xtype property as the factory method.
45502 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45503 * @param {Object} config
45506 addxtype : function()
45508 var ar = Array.prototype.slice.call(arguments, 0);
45510 for(var i = 0; i < ar.length; i++) {
45512 continue; // skip -- if this happends something invalid got sent, we
45513 // should ignore it, as basically that interface element will not show up
45514 // and that should be pretty obvious!!
45517 if (Roo.form[ar[i].xtype]) {
45519 var fe = Roo.factory(ar[i], Roo.form);
45525 fe.store.form = this;
45530 this.allItems.push(fe);
45531 if (fe.items && fe.addxtype) {
45532 fe.addxtype.apply(fe, fe.items);
45542 // console.log('adding ' + ar[i].xtype);
45544 if (ar[i].xtype == 'Button') {
45545 //console.log('adding button');
45546 //console.log(ar[i]);
45547 this.addButton(ar[i]);
45548 this.allItems.push(fe);
45552 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45553 alert('end is not supported on xtype any more, use items');
45555 // //console.log('adding end');
45563 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45564 * option "monitorValid"
45566 startMonitoring : function(){
45569 Roo.TaskMgr.start({
45570 run : this.bindHandler,
45571 interval : this.monitorPoll || 200,
45578 * Stops monitoring of the valid state of this form
45580 stopMonitoring : function(){
45581 this.bound = false;
45585 bindHandler : function(){
45587 return false; // stops binding
45590 this.items.each(function(f){
45591 if(!f.isValid(true)){
45596 for(var i = 0, len = this.buttons.length; i < len; i++){
45597 var btn = this.buttons[i];
45598 if(btn.formBind === true && btn.disabled === valid){
45599 btn.setDisabled(!valid);
45602 this.fireEvent('clientvalidation', this, valid);
45616 Roo.Form = Roo.form.Form;
45619 * Ext JS Library 1.1.1
45620 * Copyright(c) 2006-2007, Ext JS, LLC.
45622 * Originally Released Under LGPL - original licence link has changed is not relivant.
45625 * <script type="text/javascript">
45628 // as we use this in bootstrap.
45629 Roo.namespace('Roo.form');
45631 * @class Roo.form.Action
45632 * Internal Class used to handle form actions
45634 * @param {Roo.form.BasicForm} el The form element or its id
45635 * @param {Object} config Configuration options
45640 // define the action interface
45641 Roo.form.Action = function(form, options){
45643 this.options = options || {};
45646 * Client Validation Failed
45649 Roo.form.Action.CLIENT_INVALID = 'client';
45651 * Server Validation Failed
45654 Roo.form.Action.SERVER_INVALID = 'server';
45656 * Connect to Server Failed
45659 Roo.form.Action.CONNECT_FAILURE = 'connect';
45661 * Reading Data from Server Failed
45664 Roo.form.Action.LOAD_FAILURE = 'load';
45666 Roo.form.Action.prototype = {
45668 failureType : undefined,
45669 response : undefined,
45670 result : undefined,
45672 // interface method
45673 run : function(options){
45677 // interface method
45678 success : function(response){
45682 // interface method
45683 handleResponse : function(response){
45687 // default connection failure
45688 failure : function(response){
45690 this.response = response;
45691 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45692 this.form.afterAction(this, false);
45695 processResponse : function(response){
45696 this.response = response;
45697 if(!response.responseText){
45700 this.result = this.handleResponse(response);
45701 return this.result;
45704 // utility functions used internally
45705 getUrl : function(appendParams){
45706 var url = this.options.url || this.form.url || this.form.el.dom.action;
45708 var p = this.getParams();
45710 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
45716 getMethod : function(){
45717 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
45720 getParams : function(){
45721 var bp = this.form.baseParams;
45722 var p = this.options.params;
45724 if(typeof p == "object"){
45725 p = Roo.urlEncode(Roo.applyIf(p, bp));
45726 }else if(typeof p == 'string' && bp){
45727 p += '&' + Roo.urlEncode(bp);
45730 p = Roo.urlEncode(bp);
45735 createCallback : function(){
45737 success: this.success,
45738 failure: this.failure,
45740 timeout: (this.form.timeout*1000),
45741 upload: this.form.fileUpload ? this.success : undefined
45746 Roo.form.Action.Submit = function(form, options){
45747 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
45750 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
45753 haveProgress : false,
45754 uploadComplete : false,
45756 // uploadProgress indicator.
45757 uploadProgress : function()
45759 if (!this.form.progressUrl) {
45763 if (!this.haveProgress) {
45764 Roo.MessageBox.progress("Uploading", "Uploading");
45766 if (this.uploadComplete) {
45767 Roo.MessageBox.hide();
45771 this.haveProgress = true;
45773 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
45775 var c = new Roo.data.Connection();
45777 url : this.form.progressUrl,
45782 success : function(req){
45783 //console.log(data);
45787 rdata = Roo.decode(req.responseText)
45789 Roo.log("Invalid data from server..");
45793 if (!rdata || !rdata.success) {
45795 Roo.MessageBox.alert(Roo.encode(rdata));
45798 var data = rdata.data;
45800 if (this.uploadComplete) {
45801 Roo.MessageBox.hide();
45806 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
45807 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
45810 this.uploadProgress.defer(2000,this);
45813 failure: function(data) {
45814 Roo.log('progress url failed ');
45825 // run get Values on the form, so it syncs any secondary forms.
45826 this.form.getValues();
45828 var o = this.options;
45829 var method = this.getMethod();
45830 var isPost = method == 'POST';
45831 if(o.clientValidation === false || this.form.isValid()){
45833 if (this.form.progressUrl) {
45834 this.form.findField('UPLOAD_IDENTIFIER').setValue(
45835 (new Date() * 1) + '' + Math.random());
45840 Roo.Ajax.request(Roo.apply(this.createCallback(), {
45841 form:this.form.el.dom,
45842 url:this.getUrl(!isPost),
45844 params:isPost ? this.getParams() : null,
45845 isUpload: this.form.fileUpload
45848 this.uploadProgress();
45850 }else if (o.clientValidation !== false){ // client validation failed
45851 this.failureType = Roo.form.Action.CLIENT_INVALID;
45852 this.form.afterAction(this, false);
45856 success : function(response)
45858 this.uploadComplete= true;
45859 if (this.haveProgress) {
45860 Roo.MessageBox.hide();
45864 var result = this.processResponse(response);
45865 if(result === true || result.success){
45866 this.form.afterAction(this, true);
45870 this.form.markInvalid(result.errors);
45871 this.failureType = Roo.form.Action.SERVER_INVALID;
45873 this.form.afterAction(this, false);
45875 failure : function(response)
45877 this.uploadComplete= true;
45878 if (this.haveProgress) {
45879 Roo.MessageBox.hide();
45882 this.response = response;
45883 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45884 this.form.afterAction(this, false);
45887 handleResponse : function(response){
45888 if(this.form.errorReader){
45889 var rs = this.form.errorReader.read(response);
45892 for(var i = 0, len = rs.records.length; i < len; i++) {
45893 var r = rs.records[i];
45894 errors[i] = r.data;
45897 if(errors.length < 1){
45901 success : rs.success,
45907 ret = Roo.decode(response.responseText);
45911 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
45921 Roo.form.Action.Load = function(form, options){
45922 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
45923 this.reader = this.form.reader;
45926 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
45931 Roo.Ajax.request(Roo.apply(
45932 this.createCallback(), {
45933 method:this.getMethod(),
45934 url:this.getUrl(false),
45935 params:this.getParams()
45939 success : function(response){
45941 var result = this.processResponse(response);
45942 if(result === true || !result.success || !result.data){
45943 this.failureType = Roo.form.Action.LOAD_FAILURE;
45944 this.form.afterAction(this, false);
45947 this.form.clearInvalid();
45948 this.form.setValues(result.data);
45949 this.form.afterAction(this, true);
45952 handleResponse : function(response){
45953 if(this.form.reader){
45954 var rs = this.form.reader.read(response);
45955 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
45957 success : rs.success,
45961 return Roo.decode(response.responseText);
45965 Roo.form.Action.ACTION_TYPES = {
45966 'load' : Roo.form.Action.Load,
45967 'submit' : Roo.form.Action.Submit
45970 * Ext JS Library 1.1.1
45971 * Copyright(c) 2006-2007, Ext JS, LLC.
45973 * Originally Released Under LGPL - original licence link has changed is not relivant.
45976 * <script type="text/javascript">
45980 * @class Roo.form.Layout
45981 * @extends Roo.Component
45982 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45984 * @param {Object} config Configuration options
45986 Roo.form.Layout = function(config){
45988 if (config.items) {
45989 xitems = config.items;
45990 delete config.items;
45992 Roo.form.Layout.superclass.constructor.call(this, config);
45994 Roo.each(xitems, this.addxtype, this);
45998 Roo.extend(Roo.form.Layout, Roo.Component, {
46000 * @cfg {String/Object} autoCreate
46001 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
46004 * @cfg {String/Object/Function} style
46005 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
46006 * a function which returns such a specification.
46009 * @cfg {String} labelAlign
46010 * Valid values are "left," "top" and "right" (defaults to "left")
46013 * @cfg {Number} labelWidth
46014 * Fixed width in pixels of all field labels (defaults to undefined)
46017 * @cfg {Boolean} clear
46018 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
46022 * @cfg {String} labelSeparator
46023 * The separator to use after field labels (defaults to ':')
46025 labelSeparator : ':',
46027 * @cfg {Boolean} hideLabels
46028 * True to suppress the display of field labels in this layout (defaults to false)
46030 hideLabels : false,
46033 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
46038 onRender : function(ct, position){
46039 if(this.el){ // from markup
46040 this.el = Roo.get(this.el);
46041 }else { // generate
46042 var cfg = this.getAutoCreate();
46043 this.el = ct.createChild(cfg, position);
46046 this.el.applyStyles(this.style);
46048 if(this.labelAlign){
46049 this.el.addClass('x-form-label-'+this.labelAlign);
46051 if(this.hideLabels){
46052 this.labelStyle = "display:none";
46053 this.elementStyle = "padding-left:0;";
46055 if(typeof this.labelWidth == 'number'){
46056 this.labelStyle = "width:"+this.labelWidth+"px;";
46057 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
46059 if(this.labelAlign == 'top'){
46060 this.labelStyle = "width:auto;";
46061 this.elementStyle = "padding-left:0;";
46064 var stack = this.stack;
46065 var slen = stack.length;
46067 if(!this.fieldTpl){
46068 var t = new Roo.Template(
46069 '<div class="x-form-item {5}">',
46070 '<label for="{0}" style="{2}">{1}{4}</label>',
46071 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46073 '</div><div class="x-form-clear-left"></div>'
46075 t.disableFormats = true;
46077 Roo.form.Layout.prototype.fieldTpl = t;
46079 for(var i = 0; i < slen; i++) {
46080 if(stack[i].isFormField){
46081 this.renderField(stack[i]);
46083 this.renderComponent(stack[i]);
46088 this.el.createChild({cls:'x-form-clear'});
46093 renderField : function(f){
46094 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
46097 f.labelStyle||this.labelStyle||'', //2
46098 this.elementStyle||'', //3
46099 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
46100 f.itemCls||this.itemCls||'' //5
46101 ], true).getPrevSibling());
46105 renderComponent : function(c){
46106 c.render(c.isLayout ? this.el : this.el.createChild());
46109 * Adds a object form elements (using the xtype property as the factory method.)
46110 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
46111 * @param {Object} config
46113 addxtype : function(o)
46115 // create the lement.
46116 o.form = this.form;
46117 var fe = Roo.factory(o, Roo.form);
46118 this.form.allItems.push(fe);
46119 this.stack.push(fe);
46121 if (fe.isFormField) {
46122 this.form.items.add(fe);
46130 * @class Roo.form.Column
46131 * @extends Roo.form.Layout
46132 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
46134 * @param {Object} config Configuration options
46136 Roo.form.Column = function(config){
46137 Roo.form.Column.superclass.constructor.call(this, config);
46140 Roo.extend(Roo.form.Column, Roo.form.Layout, {
46142 * @cfg {Number/String} width
46143 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46146 * @cfg {String/Object} autoCreate
46147 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
46151 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
46154 onRender : function(ct, position){
46155 Roo.form.Column.superclass.onRender.call(this, ct, position);
46157 this.el.setWidth(this.width);
46164 * @class Roo.form.Row
46165 * @extends Roo.form.Layout
46166 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46168 * @param {Object} config Configuration options
46172 Roo.form.Row = function(config){
46173 Roo.form.Row.superclass.constructor.call(this, config);
46176 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46178 * @cfg {Number/String} width
46179 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46182 * @cfg {Number/String} height
46183 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46185 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46189 onRender : function(ct, position){
46190 //console.log('row render');
46192 var t = new Roo.Template(
46193 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46194 '<label for="{0}" style="{2}">{1}{4}</label>',
46195 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46199 t.disableFormats = true;
46201 Roo.form.Layout.prototype.rowTpl = t;
46203 this.fieldTpl = this.rowTpl;
46205 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46206 var labelWidth = 100;
46208 if ((this.labelAlign != 'top')) {
46209 if (typeof this.labelWidth == 'number') {
46210 labelWidth = this.labelWidth
46212 this.padWidth = 20 + labelWidth;
46216 Roo.form.Column.superclass.onRender.call(this, ct, position);
46218 this.el.setWidth(this.width);
46221 this.el.setHeight(this.height);
46226 renderField : function(f){
46227 f.fieldEl = this.fieldTpl.append(this.el, [
46228 f.id, f.fieldLabel,
46229 f.labelStyle||this.labelStyle||'',
46230 this.elementStyle||'',
46231 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46232 f.itemCls||this.itemCls||'',
46233 f.width ? f.width + this.padWidth : 160 + this.padWidth
46240 * @class Roo.form.FieldSet
46241 * @extends Roo.form.Layout
46242 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46244 * @param {Object} config Configuration options
46246 Roo.form.FieldSet = function(config){
46247 Roo.form.FieldSet.superclass.constructor.call(this, config);
46250 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46252 * @cfg {String} legend
46253 * The text to display as the legend for the FieldSet (defaults to '')
46256 * @cfg {String/Object} autoCreate
46257 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46261 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46264 onRender : function(ct, position){
46265 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46267 this.setLegend(this.legend);
46272 setLegend : function(text){
46274 this.el.child('legend').update(text);
46279 * Ext JS Library 1.1.1
46280 * Copyright(c) 2006-2007, Ext JS, LLC.
46282 * Originally Released Under LGPL - original licence link has changed is not relivant.
46285 * <script type="text/javascript">
46288 * @class Roo.form.VTypes
46289 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46292 Roo.form.VTypes = function(){
46293 // closure these in so they are only created once.
46294 var alpha = /^[a-zA-Z_]+$/;
46295 var alphanum = /^[a-zA-Z0-9_]+$/;
46296 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46297 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46299 // All these messages and functions are configurable
46302 * The function used to validate email addresses
46303 * @param {String} value The email address
46305 'email' : function(v){
46306 return email.test(v);
46309 * The error text to display when the email validation function returns false
46312 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46314 * The keystroke filter mask to be applied on email input
46317 'emailMask' : /[a-z0-9_\.\-@]/i,
46320 * The function used to validate URLs
46321 * @param {String} value The URL
46323 'url' : function(v){
46324 return url.test(v);
46327 * The error text to display when the url validation function returns false
46330 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46333 * The function used to validate alpha values
46334 * @param {String} value The value
46336 'alpha' : function(v){
46337 return alpha.test(v);
46340 * The error text to display when the alpha validation function returns false
46343 'alphaText' : 'This field should only contain letters and _',
46345 * The keystroke filter mask to be applied on alpha input
46348 'alphaMask' : /[a-z_]/i,
46351 * The function used to validate alphanumeric values
46352 * @param {String} value The value
46354 'alphanum' : function(v){
46355 return alphanum.test(v);
46358 * The error text to display when the alphanumeric validation function returns false
46361 'alphanumText' : 'This field should only contain letters, numbers and _',
46363 * The keystroke filter mask to be applied on alphanumeric input
46366 'alphanumMask' : /[a-z0-9_]/i
46368 }();//<script type="text/javascript">
46371 * @class Roo.form.FCKeditor
46372 * @extends Roo.form.TextArea
46373 * Wrapper around the FCKEditor http://www.fckeditor.net
46375 * Creates a new FCKeditor
46376 * @param {Object} config Configuration options
46378 Roo.form.FCKeditor = function(config){
46379 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46382 * @event editorinit
46383 * Fired when the editor is initialized - you can add extra handlers here..
46384 * @param {FCKeditor} this
46385 * @param {Object} the FCK object.
46392 Roo.form.FCKeditor.editors = { };
46393 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46395 //defaultAutoCreate : {
46396 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46400 * @cfg {Object} fck options - see fck manual for details.
46405 * @cfg {Object} fck toolbar set (Basic or Default)
46407 toolbarSet : 'Basic',
46409 * @cfg {Object} fck BasePath
46411 basePath : '/fckeditor/',
46419 onRender : function(ct, position)
46422 this.defaultAutoCreate = {
46424 style:"width:300px;height:60px;",
46425 autocomplete: "off"
46428 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46431 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46432 if(this.preventScrollbars){
46433 this.el.setStyle("overflow", "hidden");
46435 this.el.setHeight(this.growMin);
46438 //console.log('onrender' + this.getId() );
46439 Roo.form.FCKeditor.editors[this.getId()] = this;
46442 this.replaceTextarea() ;
46446 getEditor : function() {
46447 return this.fckEditor;
46450 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46451 * @param {Mixed} value The value to set
46455 setValue : function(value)
46457 //console.log('setValue: ' + value);
46459 if(typeof(value) == 'undefined') { // not sure why this is happending...
46462 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46464 //if(!this.el || !this.getEditor()) {
46465 // this.value = value;
46466 //this.setValue.defer(100,this,[value]);
46470 if(!this.getEditor()) {
46474 this.getEditor().SetData(value);
46481 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46482 * @return {Mixed} value The field value
46484 getValue : function()
46487 if (this.frame && this.frame.dom.style.display == 'none') {
46488 return Roo.form.FCKeditor.superclass.getValue.call(this);
46491 if(!this.el || !this.getEditor()) {
46493 // this.getValue.defer(100,this);
46498 var value=this.getEditor().GetData();
46499 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46500 return Roo.form.FCKeditor.superclass.getValue.call(this);
46506 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46507 * @return {Mixed} value The field value
46509 getRawValue : function()
46511 if (this.frame && this.frame.dom.style.display == 'none') {
46512 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46515 if(!this.el || !this.getEditor()) {
46516 //this.getRawValue.defer(100,this);
46523 var value=this.getEditor().GetData();
46524 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46525 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46529 setSize : function(w,h) {
46533 //if (this.frame && this.frame.dom.style.display == 'none') {
46534 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46537 //if(!this.el || !this.getEditor()) {
46538 // this.setSize.defer(100,this, [w,h]);
46544 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46546 this.frame.dom.setAttribute('width', w);
46547 this.frame.dom.setAttribute('height', h);
46548 this.frame.setSize(w,h);
46552 toggleSourceEdit : function(value) {
46556 this.el.dom.style.display = value ? '' : 'none';
46557 this.frame.dom.style.display = value ? 'none' : '';
46562 focus: function(tag)
46564 if (this.frame.dom.style.display == 'none') {
46565 return Roo.form.FCKeditor.superclass.focus.call(this);
46567 if(!this.el || !this.getEditor()) {
46568 this.focus.defer(100,this, [tag]);
46575 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46576 this.getEditor().Focus();
46578 if (!this.getEditor().Selection.GetSelection()) {
46579 this.focus.defer(100,this, [tag]);
46584 var r = this.getEditor().EditorDocument.createRange();
46585 r.setStart(tgs[0],0);
46586 r.setEnd(tgs[0],0);
46587 this.getEditor().Selection.GetSelection().removeAllRanges();
46588 this.getEditor().Selection.GetSelection().addRange(r);
46589 this.getEditor().Focus();
46596 replaceTextarea : function()
46598 if ( document.getElementById( this.getId() + '___Frame' ) )
46600 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46602 // We must check the elements firstly using the Id and then the name.
46603 var oTextarea = document.getElementById( this.getId() );
46605 var colElementsByName = document.getElementsByName( this.getId() ) ;
46607 oTextarea.style.display = 'none' ;
46609 if ( oTextarea.tabIndex ) {
46610 this.TabIndex = oTextarea.tabIndex ;
46613 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46614 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46615 this.frame = Roo.get(this.getId() + '___Frame')
46618 _getConfigHtml : function()
46622 for ( var o in this.fckconfig ) {
46623 sConfig += sConfig.length > 0 ? '&' : '';
46624 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
46627 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
46631 _getIFrameHtml : function()
46633 var sFile = 'fckeditor.html' ;
46634 /* no idea what this is about..
46637 if ( (/fcksource=true/i).test( window.top.location.search ) )
46638 sFile = 'fckeditor.original.html' ;
46643 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
46644 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
46647 var html = '<iframe id="' + this.getId() +
46648 '___Frame" src="' + sLink +
46649 '" width="' + this.width +
46650 '" height="' + this.height + '"' +
46651 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
46652 ' frameborder="0" scrolling="no"></iframe>' ;
46657 _insertHtmlBefore : function( html, element )
46659 if ( element.insertAdjacentHTML ) {
46661 element.insertAdjacentHTML( 'beforeBegin', html ) ;
46663 var oRange = document.createRange() ;
46664 oRange.setStartBefore( element ) ;
46665 var oFragment = oRange.createContextualFragment( html );
46666 element.parentNode.insertBefore( oFragment, element ) ;
46679 //Roo.reg('fckeditor', Roo.form.FCKeditor);
46681 function FCKeditor_OnComplete(editorInstance){
46682 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
46683 f.fckEditor = editorInstance;
46684 //console.log("loaded");
46685 f.fireEvent('editorinit', f, editorInstance);
46705 //<script type="text/javascript">
46707 * @class Roo.form.GridField
46708 * @extends Roo.form.Field
46709 * Embed a grid (or editable grid into a form)
46712 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
46714 * xgrid.store = Roo.data.Store
46715 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
46716 * xgrid.store.reader = Roo.data.JsonReader
46720 * Creates a new GridField
46721 * @param {Object} config Configuration options
46723 Roo.form.GridField = function(config){
46724 Roo.form.GridField.superclass.constructor.call(this, config);
46728 Roo.extend(Roo.form.GridField, Roo.form.Field, {
46730 * @cfg {Number} width - used to restrict width of grid..
46734 * @cfg {Number} height - used to restrict height of grid..
46738 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
46744 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46745 * {tag: "input", type: "checkbox", autocomplete: "off"})
46747 // defaultAutoCreate : { tag: 'div' },
46748 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46750 * @cfg {String} addTitle Text to include for adding a title.
46754 onResize : function(){
46755 Roo.form.Field.superclass.onResize.apply(this, arguments);
46758 initEvents : function(){
46759 // Roo.form.Checkbox.superclass.initEvents.call(this);
46760 // has no events...
46765 getResizeEl : function(){
46769 getPositionEl : function(){
46774 onRender : function(ct, position){
46776 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
46777 var style = this.style;
46780 Roo.form.GridField.superclass.onRender.call(this, ct, position);
46781 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
46782 this.viewEl = this.wrap.createChild({ tag: 'div' });
46784 this.viewEl.applyStyles(style);
46787 this.viewEl.setWidth(this.width);
46790 this.viewEl.setHeight(this.height);
46792 //if(this.inputValue !== undefined){
46793 //this.setValue(this.value);
46796 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
46799 this.grid.render();
46800 this.grid.getDataSource().on('remove', this.refreshValue, this);
46801 this.grid.getDataSource().on('update', this.refreshValue, this);
46802 this.grid.on('afteredit', this.refreshValue, this);
46808 * Sets the value of the item.
46809 * @param {String} either an object or a string..
46811 setValue : function(v){
46813 v = v || []; // empty set..
46814 // this does not seem smart - it really only affects memoryproxy grids..
46815 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
46816 var ds = this.grid.getDataSource();
46817 // assumes a json reader..
46819 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
46820 ds.loadData( data);
46822 // clear selection so it does not get stale.
46823 if (this.grid.sm) {
46824 this.grid.sm.clearSelections();
46827 Roo.form.GridField.superclass.setValue.call(this, v);
46828 this.refreshValue();
46829 // should load data in the grid really....
46833 refreshValue: function() {
46835 this.grid.getDataSource().each(function(r) {
46838 this.el.dom.value = Roo.encode(val);
46846 * Ext JS Library 1.1.1
46847 * Copyright(c) 2006-2007, Ext JS, LLC.
46849 * Originally Released Under LGPL - original licence link has changed is not relivant.
46852 * <script type="text/javascript">
46855 * @class Roo.form.DisplayField
46856 * @extends Roo.form.Field
46857 * A generic Field to display non-editable data.
46859 * Creates a new Display Field item.
46860 * @param {Object} config Configuration options
46862 Roo.form.DisplayField = function(config){
46863 Roo.form.DisplayField.superclass.constructor.call(this, config);
46867 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
46868 inputType: 'hidden',
46874 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46876 focusClass : undefined,
46878 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46880 fieldClass: 'x-form-field',
46883 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
46885 valueRenderer: undefined,
46889 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46890 * {tag: "input", type: "checkbox", autocomplete: "off"})
46893 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46895 onResize : function(){
46896 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
46900 initEvents : function(){
46901 // Roo.form.Checkbox.superclass.initEvents.call(this);
46902 // has no events...
46907 getResizeEl : function(){
46911 getPositionEl : function(){
46916 onRender : function(ct, position){
46918 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
46919 //if(this.inputValue !== undefined){
46920 this.wrap = this.el.wrap();
46922 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
46924 if (this.bodyStyle) {
46925 this.viewEl.applyStyles(this.bodyStyle);
46927 //this.viewEl.setStyle('padding', '2px');
46929 this.setValue(this.value);
46934 initValue : Roo.emptyFn,
46939 onClick : function(){
46944 * Sets the checked state of the checkbox.
46945 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
46947 setValue : function(v){
46949 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
46950 // this might be called before we have a dom element..
46951 if (!this.viewEl) {
46954 this.viewEl.dom.innerHTML = html;
46955 Roo.form.DisplayField.superclass.setValue.call(this, v);
46965 * @class Roo.form.DayPicker
46966 * @extends Roo.form.Field
46967 * A Day picker show [M] [T] [W] ....
46969 * Creates a new Day Picker
46970 * @param {Object} config Configuration options
46972 Roo.form.DayPicker= function(config){
46973 Roo.form.DayPicker.superclass.constructor.call(this, config);
46977 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
46979 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46981 focusClass : undefined,
46983 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46985 fieldClass: "x-form-field",
46988 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46989 * {tag: "input", type: "checkbox", autocomplete: "off"})
46991 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
46994 actionMode : 'viewEl',
46998 inputType : 'hidden',
47001 inputElement: false, // real input element?
47002 basedOn: false, // ????
47004 isFormField: true, // not sure where this is needed!!!!
47006 onResize : function(){
47007 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
47008 if(!this.boxLabel){
47009 this.el.alignTo(this.wrap, 'c-c');
47013 initEvents : function(){
47014 Roo.form.Checkbox.superclass.initEvents.call(this);
47015 this.el.on("click", this.onClick, this);
47016 this.el.on("change", this.onClick, this);
47020 getResizeEl : function(){
47024 getPositionEl : function(){
47030 onRender : function(ct, position){
47031 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
47033 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
47035 var r1 = '<table><tr>';
47036 var r2 = '<tr class="x-form-daypick-icons">';
47037 for (var i=0; i < 7; i++) {
47038 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
47039 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
47042 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
47043 viewEl.select('img').on('click', this.onClick, this);
47044 this.viewEl = viewEl;
47047 // this will not work on Chrome!!!
47048 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
47049 this.el.on('propertychange', this.setFromHidden, this); //ie
47057 initValue : Roo.emptyFn,
47060 * Returns the checked state of the checkbox.
47061 * @return {Boolean} True if checked, else false
47063 getValue : function(){
47064 return this.el.dom.value;
47069 onClick : function(e){
47070 //this.setChecked(!this.checked);
47071 Roo.get(e.target).toggleClass('x-menu-item-checked');
47072 this.refreshValue();
47073 //if(this.el.dom.checked != this.checked){
47074 // this.setValue(this.el.dom.checked);
47079 refreshValue : function()
47082 this.viewEl.select('img',true).each(function(e,i,n) {
47083 val += e.is(".x-menu-item-checked") ? String(n) : '';
47085 this.setValue(val, true);
47089 * Sets the checked state of the checkbox.
47090 * On is always based on a string comparison between inputValue and the param.
47091 * @param {Boolean/String} value - the value to set
47092 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
47094 setValue : function(v,suppressEvent){
47095 if (!this.el.dom) {
47098 var old = this.el.dom.value ;
47099 this.el.dom.value = v;
47100 if (suppressEvent) {
47104 // update display..
47105 this.viewEl.select('img',true).each(function(e,i,n) {
47107 var on = e.is(".x-menu-item-checked");
47108 var newv = v.indexOf(String(n)) > -1;
47110 e.toggleClass('x-menu-item-checked');
47116 this.fireEvent('change', this, v, old);
47121 // handle setting of hidden value by some other method!!?!?
47122 setFromHidden: function()
47127 //console.log("SET FROM HIDDEN");
47128 //alert('setFrom hidden');
47129 this.setValue(this.el.dom.value);
47132 onDestroy : function()
47135 Roo.get(this.viewEl).remove();
47138 Roo.form.DayPicker.superclass.onDestroy.call(this);
47142 * RooJS Library 1.1.1
47143 * Copyright(c) 2008-2011 Alan Knowles
47150 * @class Roo.form.ComboCheck
47151 * @extends Roo.form.ComboBox
47152 * A combobox for multiple select items.
47154 * FIXME - could do with a reset button..
47157 * Create a new ComboCheck
47158 * @param {Object} config Configuration options
47160 Roo.form.ComboCheck = function(config){
47161 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47162 // should verify some data...
47164 // hiddenName = required..
47165 // displayField = required
47166 // valudField == required
47167 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47169 Roo.each(req, function(e) {
47170 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47171 throw "Roo.form.ComboCheck : missing value for: " + e;
47178 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47183 selectedClass: 'x-menu-item-checked',
47186 onRender : function(ct, position){
47192 var cls = 'x-combo-list';
47195 this.tpl = new Roo.Template({
47196 html : '<div class="'+cls+'-item x-menu-check-item">' +
47197 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47198 '<span>{' + this.displayField + '}</span>' +
47205 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47206 this.view.singleSelect = false;
47207 this.view.multiSelect = true;
47208 this.view.toggleSelect = true;
47209 this.pageTb.add(new Roo.Toolbar.Fill(), {
47212 handler: function()
47219 onViewOver : function(e, t){
47225 onViewClick : function(doFocus,index){
47229 select: function () {
47230 //Roo.log("SELECT CALLED");
47233 selectByValue : function(xv, scrollIntoView){
47234 var ar = this.getValueArray();
47237 Roo.each(ar, function(v) {
47238 if(v === undefined || v === null){
47241 var r = this.findRecord(this.valueField, v);
47243 sels.push(this.store.indexOf(r))
47247 this.view.select(sels);
47253 onSelect : function(record, index){
47254 // Roo.log("onselect Called");
47255 // this is only called by the clear button now..
47256 this.view.clearSelections();
47257 this.setValue('[]');
47258 if (this.value != this.valueBefore) {
47259 this.fireEvent('change', this, this.value, this.valueBefore);
47260 this.valueBefore = this.value;
47263 getValueArray : function()
47268 //Roo.log(this.value);
47269 if (typeof(this.value) == 'undefined') {
47272 var ar = Roo.decode(this.value);
47273 return ar instanceof Array ? ar : []; //?? valid?
47276 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47281 expand : function ()
47284 Roo.form.ComboCheck.superclass.expand.call(this);
47285 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47286 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47291 collapse : function(){
47292 Roo.form.ComboCheck.superclass.collapse.call(this);
47293 var sl = this.view.getSelectedIndexes();
47294 var st = this.store;
47298 Roo.each(sl, function(i) {
47300 nv.push(r.get(this.valueField));
47302 this.setValue(Roo.encode(nv));
47303 if (this.value != this.valueBefore) {
47305 this.fireEvent('change', this, this.value, this.valueBefore);
47306 this.valueBefore = this.value;
47311 setValue : function(v){
47315 var vals = this.getValueArray();
47317 Roo.each(vals, function(k) {
47318 var r = this.findRecord(this.valueField, k);
47320 tv.push(r.data[this.displayField]);
47321 }else if(this.valueNotFoundText !== undefined){
47322 tv.push( this.valueNotFoundText );
47327 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47328 this.hiddenField.value = v;
47334 * Ext JS Library 1.1.1
47335 * Copyright(c) 2006-2007, Ext JS, LLC.
47337 * Originally Released Under LGPL - original licence link has changed is not relivant.
47340 * <script type="text/javascript">
47344 * @class Roo.form.Signature
47345 * @extends Roo.form.Field
47349 * @param {Object} config Configuration options
47352 Roo.form.Signature = function(config){
47353 Roo.form.Signature.superclass.constructor.call(this, config);
47355 this.addEvents({// not in used??
47358 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47359 * @param {Roo.form.Signature} combo This combo box
47364 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47365 * @param {Roo.form.ComboBox} combo This combo box
47366 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47372 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47374 * @cfg {Object} labels Label to use when rendering a form.
47378 * confirm : "Confirm"
47383 confirm : "Confirm"
47386 * @cfg {Number} width The signature panel width (defaults to 300)
47390 * @cfg {Number} height The signature panel height (defaults to 100)
47394 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47396 allowBlank : false,
47399 // {Object} signPanel The signature SVG panel element (defaults to {})
47401 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47402 isMouseDown : false,
47403 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47404 isConfirmed : false,
47405 // {String} signatureTmp SVG mapping string (defaults to empty string)
47409 defaultAutoCreate : { // modified by initCompnoent..
47415 onRender : function(ct, position){
47417 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47419 this.wrap = this.el.wrap({
47420 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47423 this.createToolbar(this);
47424 this.signPanel = this.wrap.createChild({
47426 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47430 this.svgID = Roo.id();
47431 this.svgEl = this.signPanel.createChild({
47432 xmlns : 'http://www.w3.org/2000/svg',
47434 id : this.svgID + "-svg",
47436 height: this.height,
47437 viewBox: '0 0 '+this.width+' '+this.height,
47441 id: this.svgID + "-svg-r",
47443 height: this.height,
47448 id: this.svgID + "-svg-l",
47450 y1: (this.height*0.8), // start set the line in 80% of height
47451 x2: this.width, // end
47452 y2: (this.height*0.8), // end set the line in 80% of height
47454 'stroke-width': "1",
47455 'stroke-dasharray': "3",
47456 'shape-rendering': "crispEdges",
47457 'pointer-events': "none"
47461 id: this.svgID + "-svg-p",
47463 'stroke-width': "3",
47465 'pointer-events': 'none'
47470 this.svgBox = this.svgEl.dom.getScreenCTM();
47472 createSVG : function(){
47473 var svg = this.signPanel;
47474 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47477 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47478 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47479 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47480 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47481 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47482 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47483 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47486 isTouchEvent : function(e){
47487 return e.type.match(/^touch/);
47489 getCoords : function (e) {
47490 var pt = this.svgEl.dom.createSVGPoint();
47493 if (this.isTouchEvent(e)) {
47494 pt.x = e.targetTouches[0].clientX
47495 pt.y = e.targetTouches[0].clientY;
47497 var a = this.svgEl.dom.getScreenCTM();
47498 var b = a.inverse();
47499 var mx = pt.matrixTransform(b);
47500 return mx.x + ',' + mx.y;
47502 //mouse event headler
47503 down : function (e) {
47504 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47505 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47507 this.isMouseDown = true;
47509 e.preventDefault();
47511 move : function (e) {
47512 if (this.isMouseDown) {
47513 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47514 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47517 e.preventDefault();
47519 up : function (e) {
47520 this.isMouseDown = false;
47521 var sp = this.signatureTmp.split(' ');
47524 if(!sp[sp.length-2].match(/^L/)){
47528 this.signatureTmp = sp.join(" ");
47531 if(this.getValue() != this.signatureTmp){
47532 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47533 this.isConfirmed = false;
47535 e.preventDefault();
47539 * Protected method that will not generally be called directly. It
47540 * is called when the editor creates its toolbar. Override this method if you need to
47541 * add custom toolbar buttons.
47542 * @param {HtmlEditor} editor
47544 createToolbar : function(editor){
47545 function btn(id, toggle, handler){
47546 var xid = fid + '-'+ id ;
47550 cls : 'x-btn-icon x-edit-'+id,
47551 enableToggle:toggle !== false,
47552 scope: editor, // was editor...
47553 handler:handler||editor.relayBtnCmd,
47554 clickEvent:'mousedown',
47555 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47561 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47565 cls : ' x-signature-btn x-signature-'+id,
47566 scope: editor, // was editor...
47567 handler: this.reset,
47568 clickEvent:'mousedown',
47569 text: this.labels.clear
47576 cls : ' x-signature-btn x-signature-'+id,
47577 scope: editor, // was editor...
47578 handler: this.confirmHandler,
47579 clickEvent:'mousedown',
47580 text: this.labels.confirm
47587 * when user is clicked confirm then show this image.....
47589 * @return {String} Image Data URI
47591 getImageDataURI : function(){
47592 var svg = this.svgEl.dom.parentNode.innerHTML;
47593 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47598 * @return {Boolean} this.isConfirmed
47600 getConfirmed : function(){
47601 return this.isConfirmed;
47605 * @return {Number} this.width
47607 getWidth : function(){
47612 * @return {Number} this.height
47614 getHeight : function(){
47615 return this.height;
47618 getSignature : function(){
47619 return this.signatureTmp;
47622 reset : function(){
47623 this.signatureTmp = '';
47624 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47625 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
47626 this.isConfirmed = false;
47627 Roo.form.Signature.superclass.reset.call(this);
47629 setSignature : function(s){
47630 this.signatureTmp = s;
47631 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47632 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
47634 this.isConfirmed = false;
47635 Roo.form.Signature.superclass.reset.call(this);
47638 // Roo.log(this.signPanel.dom.contentWindow.up())
47641 setConfirmed : function(){
47645 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
47648 confirmHandler : function(){
47649 if(!this.getSignature()){
47653 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
47654 this.setValue(this.getSignature());
47655 this.isConfirmed = true;
47657 this.fireEvent('confirm', this);
47660 // Subclasses should provide the validation implementation by overriding this
47661 validateValue : function(value){
47662 if(this.allowBlank){
47666 if(this.isConfirmed){
47673 * Ext JS Library 1.1.1
47674 * Copyright(c) 2006-2007, Ext JS, LLC.
47676 * Originally Released Under LGPL - original licence link has changed is not relivant.
47679 * <script type="text/javascript">
47684 * @class Roo.form.ComboBox
47685 * @extends Roo.form.TriggerField
47686 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
47688 * Create a new ComboBox.
47689 * @param {Object} config Configuration options
47691 Roo.form.Select = function(config){
47692 Roo.form.Select.superclass.constructor.call(this, config);
47696 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
47698 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
47701 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
47702 * rendering into an Roo.Editor, defaults to false)
47705 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
47706 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
47709 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
47712 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
47713 * the dropdown list (defaults to undefined, with no header element)
47717 * @cfg {String/Roo.Template} tpl The template to use to render the output
47721 defaultAutoCreate : {tag: "select" },
47723 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
47725 listWidth: undefined,
47727 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
47728 * mode = 'remote' or 'text' if mode = 'local')
47730 displayField: undefined,
47732 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
47733 * mode = 'remote' or 'value' if mode = 'local').
47734 * Note: use of a valueField requires the user make a selection
47735 * in order for a value to be mapped.
47737 valueField: undefined,
47741 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
47742 * field's data value (defaults to the underlying DOM element's name)
47744 hiddenName: undefined,
47746 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
47750 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
47752 selectedClass: 'x-combo-selected',
47754 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
47755 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
47756 * which displays a downward arrow icon).
47758 triggerClass : 'x-form-arrow-trigger',
47760 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
47764 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
47765 * anchor positions (defaults to 'tl-bl')
47767 listAlign: 'tl-bl?',
47769 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
47773 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
47774 * query specified by the allQuery config option (defaults to 'query')
47776 triggerAction: 'query',
47778 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
47779 * (defaults to 4, does not apply if editable = false)
47783 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
47784 * delay (typeAheadDelay) if it matches a known value (defaults to false)
47788 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
47789 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
47793 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
47794 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
47798 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
47799 * when editable = true (defaults to false)
47801 selectOnFocus:false,
47803 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
47805 queryParam: 'query',
47807 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
47808 * when mode = 'remote' (defaults to 'Loading...')
47810 loadingText: 'Loading...',
47812 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
47816 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
47820 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
47821 * traditional select (defaults to true)
47825 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
47829 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
47833 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
47834 * listWidth has a higher value)
47838 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
47839 * allow the user to set arbitrary text into the field (defaults to false)
47841 forceSelection:false,
47843 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
47844 * if typeAhead = true (defaults to 250)
47846 typeAheadDelay : 250,
47848 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
47849 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
47851 valueNotFoundText : undefined,
47854 * @cfg {String} defaultValue The value displayed after loading the store.
47859 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
47861 blockFocus : false,
47864 * @cfg {Boolean} disableClear Disable showing of clear button.
47866 disableClear : false,
47868 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
47870 alwaysQuery : false,
47876 // element that contains real text value.. (when hidden is used..)
47879 onRender : function(ct, position){
47880 Roo.form.Field.prototype.onRender.call(this, ct, position);
47883 this.store.on('beforeload', this.onBeforeLoad, this);
47884 this.store.on('load', this.onLoad, this);
47885 this.store.on('loadexception', this.onLoadException, this);
47886 this.store.load({});
47894 initEvents : function(){
47895 //Roo.form.ComboBox.superclass.initEvents.call(this);
47899 onDestroy : function(){
47902 this.store.un('beforeload', this.onBeforeLoad, this);
47903 this.store.un('load', this.onLoad, this);
47904 this.store.un('loadexception', this.onLoadException, this);
47906 //Roo.form.ComboBox.superclass.onDestroy.call(this);
47910 fireKey : function(e){
47911 if(e.isNavKeyPress() && !this.list.isVisible()){
47912 this.fireEvent("specialkey", this, e);
47917 onResize: function(w, h){
47925 * Allow or prevent the user from directly editing the field text. If false is passed,
47926 * the user will only be able to select from the items defined in the dropdown list. This method
47927 * is the runtime equivalent of setting the 'editable' config option at config time.
47928 * @param {Boolean} value True to allow the user to directly edit the field text
47930 setEditable : function(value){
47935 onBeforeLoad : function(){
47937 Roo.log("Select before load");
47940 this.innerList.update(this.loadingText ?
47941 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
47942 //this.restrictHeight();
47943 this.selectedIndex = -1;
47947 onLoad : function(){
47950 var dom = this.el.dom;
47951 dom.innerHTML = '';
47952 var od = dom.ownerDocument;
47954 if (this.emptyText) {
47955 var op = od.createElement('option');
47956 op.setAttribute('value', '');
47957 op.innerHTML = String.format('{0}', this.emptyText);
47958 dom.appendChild(op);
47960 if(this.store.getCount() > 0){
47962 var vf = this.valueField;
47963 var df = this.displayField;
47964 this.store.data.each(function(r) {
47965 // which colmsn to use... testing - cdoe / title..
47966 var op = od.createElement('option');
47967 op.setAttribute('value', r.data[vf]);
47968 op.innerHTML = String.format('{0}', r.data[df]);
47969 dom.appendChild(op);
47971 if (typeof(this.defaultValue != 'undefined')) {
47972 this.setValue(this.defaultValue);
47977 //this.onEmptyResults();
47982 onLoadException : function()
47984 dom.innerHTML = '';
47986 Roo.log("Select on load exception");
47990 Roo.log(this.store.reader.jsonData);
47991 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
47992 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
47998 onTypeAhead : function(){
48003 onSelect : function(record, index){
48004 Roo.log('on select?');
48006 if(this.fireEvent('beforeselect', this, record, index) !== false){
48007 this.setFromData(index > -1 ? record.data : false);
48009 this.fireEvent('select', this, record, index);
48014 * Returns the currently selected field value or empty string if no value is set.
48015 * @return {String} value The selected value
48017 getValue : function(){
48018 var dom = this.el.dom;
48019 this.value = dom.options[dom.selectedIndex].value;
48025 * Clears any text/value currently set in the field
48027 clearValue : function(){
48029 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
48034 * Sets the specified value into the field. If the value finds a match, the corresponding record text
48035 * will be displayed in the field. If the value does not match the data value of an existing item,
48036 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
48037 * Otherwise the field will be blank (although the value will still be set).
48038 * @param {String} value The value to match
48040 setValue : function(v){
48041 var d = this.el.dom;
48042 for (var i =0; i < d.options.length;i++) {
48043 if (v == d.options[i].value) {
48044 d.selectedIndex = i;
48052 * @property {Object} the last set data for the element
48057 * Sets the value of the field based on a object which is related to the record format for the store.
48058 * @param {Object} value the value to set as. or false on reset?
48060 setFromData : function(o){
48061 Roo.log('setfrom data?');
48067 reset : function(){
48071 findRecord : function(prop, value){
48076 if(this.store.getCount() > 0){
48077 this.store.each(function(r){
48078 if(r.data[prop] == value){
48088 getName: function()
48090 // returns hidden if it's set..
48091 if (!this.rendered) {return ''};
48092 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
48100 onEmptyResults : function(){
48101 Roo.log('empty results');
48106 * Returns true if the dropdown list is expanded, else false.
48108 isExpanded : function(){
48113 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
48114 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48115 * @param {String} value The data value of the item to select
48116 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48117 * selected item if it is not currently in view (defaults to true)
48118 * @return {Boolean} True if the value matched an item in the list, else false
48120 selectByValue : function(v, scrollIntoView){
48121 Roo.log('select By Value');
48124 if(v !== undefined && v !== null){
48125 var r = this.findRecord(this.valueField || this.displayField, v);
48127 this.select(this.store.indexOf(r), scrollIntoView);
48135 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
48136 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48137 * @param {Number} index The zero-based index of the list item to select
48138 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48139 * selected item if it is not currently in view (defaults to true)
48141 select : function(index, scrollIntoView){
48142 Roo.log('select ');
48145 this.selectedIndex = index;
48146 this.view.select(index);
48147 if(scrollIntoView !== false){
48148 var el = this.view.getNode(index);
48150 this.innerList.scrollChildIntoView(el, false);
48158 validateBlur : function(){
48165 initQuery : function(){
48166 this.doQuery(this.getRawValue());
48170 doForce : function(){
48171 if(this.el.dom.value.length > 0){
48172 this.el.dom.value =
48173 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48179 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48180 * query allowing the query action to be canceled if needed.
48181 * @param {String} query The SQL query to execute
48182 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48183 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48184 * saved in the current store (defaults to false)
48186 doQuery : function(q, forceAll){
48188 Roo.log('doQuery?');
48189 if(q === undefined || q === null){
48194 forceAll: forceAll,
48198 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48202 forceAll = qe.forceAll;
48203 if(forceAll === true || (q.length >= this.minChars)){
48204 if(this.lastQuery != q || this.alwaysQuery){
48205 this.lastQuery = q;
48206 if(this.mode == 'local'){
48207 this.selectedIndex = -1;
48209 this.store.clearFilter();
48211 this.store.filter(this.displayField, q);
48215 this.store.baseParams[this.queryParam] = q;
48217 params: this.getParams(q)
48222 this.selectedIndex = -1;
48229 getParams : function(q){
48231 //p[this.queryParam] = q;
48234 p.limit = this.pageSize;
48240 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48242 collapse : function(){
48247 collapseIf : function(e){
48252 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48254 expand : function(){
48262 * @cfg {Boolean} grow
48266 * @cfg {Number} growMin
48270 * @cfg {Number} growMax
48278 setWidth : function()
48282 getResizeEl : function(){
48285 });//<script type="text/javasscript">
48289 * @class Roo.DDView
48290 * A DnD enabled version of Roo.View.
48291 * @param {Element/String} container The Element in which to create the View.
48292 * @param {String} tpl The template string used to create the markup for each element of the View
48293 * @param {Object} config The configuration properties. These include all the config options of
48294 * {@link Roo.View} plus some specific to this class.<br>
48296 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48297 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48299 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48300 .x-view-drag-insert-above {
48301 border-top:1px dotted #3366cc;
48303 .x-view-drag-insert-below {
48304 border-bottom:1px dotted #3366cc;
48310 Roo.DDView = function(container, tpl, config) {
48311 Roo.DDView.superclass.constructor.apply(this, arguments);
48312 this.getEl().setStyle("outline", "0px none");
48313 this.getEl().unselectable();
48314 if (this.dragGroup) {
48315 this.setDraggable(this.dragGroup.split(","));
48317 if (this.dropGroup) {
48318 this.setDroppable(this.dropGroup.split(","));
48320 if (this.deletable) {
48321 this.setDeletable();
48323 this.isDirtyFlag = false;
48329 Roo.extend(Roo.DDView, Roo.View, {
48330 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48331 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48332 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48333 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48337 reset: Roo.emptyFn,
48339 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48341 validate: function() {
48345 destroy: function() {
48346 this.purgeListeners();
48347 this.getEl.removeAllListeners();
48348 this.getEl().remove();
48349 if (this.dragZone) {
48350 if (this.dragZone.destroy) {
48351 this.dragZone.destroy();
48354 if (this.dropZone) {
48355 if (this.dropZone.destroy) {
48356 this.dropZone.destroy();
48361 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48362 getName: function() {
48366 /** Loads the View from a JSON string representing the Records to put into the Store. */
48367 setValue: function(v) {
48369 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48372 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48373 this.store.proxy = new Roo.data.MemoryProxy(data);
48377 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48378 getValue: function() {
48380 this.store.each(function(rec) {
48381 result += rec.id + ',';
48383 return result.substr(0, result.length - 1) + ')';
48386 getIds: function() {
48387 var i = 0, result = new Array(this.store.getCount());
48388 this.store.each(function(rec) {
48389 result[i++] = rec.id;
48394 isDirty: function() {
48395 return this.isDirtyFlag;
48399 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48400 * whole Element becomes the target, and this causes the drop gesture to append.
48402 getTargetFromEvent : function(e) {
48403 var target = e.getTarget();
48404 while ((target !== null) && (target.parentNode != this.el.dom)) {
48405 target = target.parentNode;
48408 target = this.el.dom.lastChild || this.el.dom;
48414 * Create the drag data which consists of an object which has the property "ddel" as
48415 * the drag proxy element.
48417 getDragData : function(e) {
48418 var target = this.findItemFromChild(e.getTarget());
48420 this.handleSelection(e);
48421 var selNodes = this.getSelectedNodes();
48424 copy: this.copy || (this.allowCopy && e.ctrlKey),
48428 var selectedIndices = this.getSelectedIndexes();
48429 for (var i = 0; i < selectedIndices.length; i++) {
48430 dragData.records.push(this.store.getAt(selectedIndices[i]));
48432 if (selNodes.length == 1) {
48433 dragData.ddel = target.cloneNode(true); // the div element
48435 var div = document.createElement('div'); // create the multi element drag "ghost"
48436 div.className = 'multi-proxy';
48437 for (var i = 0, len = selNodes.length; i < len; i++) {
48438 div.appendChild(selNodes[i].cloneNode(true));
48440 dragData.ddel = div;
48442 //console.log(dragData)
48443 //console.log(dragData.ddel.innerHTML)
48446 //console.log('nodragData')
48450 /** Specify to which ddGroup items in this DDView may be dragged. */
48451 setDraggable: function(ddGroup) {
48452 if (ddGroup instanceof Array) {
48453 Roo.each(ddGroup, this.setDraggable, this);
48456 if (this.dragZone) {
48457 this.dragZone.addToGroup(ddGroup);
48459 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48460 containerScroll: true,
48464 // Draggability implies selection. DragZone's mousedown selects the element.
48465 if (!this.multiSelect) { this.singleSelect = true; }
48467 // Wire the DragZone's handlers up to methods in *this*
48468 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48472 /** Specify from which ddGroup this DDView accepts drops. */
48473 setDroppable: function(ddGroup) {
48474 if (ddGroup instanceof Array) {
48475 Roo.each(ddGroup, this.setDroppable, this);
48478 if (this.dropZone) {
48479 this.dropZone.addToGroup(ddGroup);
48481 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48482 containerScroll: true,
48486 // Wire the DropZone's handlers up to methods in *this*
48487 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48488 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48489 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48490 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48491 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48495 /** Decide whether to drop above or below a View node. */
48496 getDropPoint : function(e, n, dd){
48497 if (n == this.el.dom) { return "above"; }
48498 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48499 var c = t + (b - t) / 2;
48500 var y = Roo.lib.Event.getPageY(e);
48508 onNodeEnter : function(n, dd, e, data){
48512 onNodeOver : function(n, dd, e, data){
48513 var pt = this.getDropPoint(e, n, dd);
48514 // set the insert point style on the target node
48515 var dragElClass = this.dropNotAllowed;
48518 if (pt == "above"){
48519 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48520 targetElClass = "x-view-drag-insert-above";
48522 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48523 targetElClass = "x-view-drag-insert-below";
48525 if (this.lastInsertClass != targetElClass){
48526 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48527 this.lastInsertClass = targetElClass;
48530 return dragElClass;
48533 onNodeOut : function(n, dd, e, data){
48534 this.removeDropIndicators(n);
48537 onNodeDrop : function(n, dd, e, data){
48538 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48541 var pt = this.getDropPoint(e, n, dd);
48542 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48543 if (pt == "below") { insertAt++; }
48544 for (var i = 0; i < data.records.length; i++) {
48545 var r = data.records[i];
48546 var dup = this.store.getById(r.id);
48547 if (dup && (dd != this.dragZone)) {
48548 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48551 this.store.insert(insertAt++, r.copy());
48553 data.source.isDirtyFlag = true;
48555 this.store.insert(insertAt++, r);
48557 this.isDirtyFlag = true;
48560 this.dragZone.cachedTarget = null;
48564 removeDropIndicators : function(n){
48566 Roo.fly(n).removeClass([
48567 "x-view-drag-insert-above",
48568 "x-view-drag-insert-below"]);
48569 this.lastInsertClass = "_noclass";
48574 * Utility method. Add a delete option to the DDView's context menu.
48575 * @param {String} imageUrl The URL of the "delete" icon image.
48577 setDeletable: function(imageUrl) {
48578 if (!this.singleSelect && !this.multiSelect) {
48579 this.singleSelect = true;
48581 var c = this.getContextMenu();
48582 this.contextMenu.on("itemclick", function(item) {
48585 this.remove(this.getSelectedIndexes());
48589 this.contextMenu.add({
48596 /** Return the context menu for this DDView. */
48597 getContextMenu: function() {
48598 if (!this.contextMenu) {
48599 // Create the View's context menu
48600 this.contextMenu = new Roo.menu.Menu({
48601 id: this.id + "-contextmenu"
48603 this.el.on("contextmenu", this.showContextMenu, this);
48605 return this.contextMenu;
48608 disableContextMenu: function() {
48609 if (this.contextMenu) {
48610 this.el.un("contextmenu", this.showContextMenu, this);
48614 showContextMenu: function(e, item) {
48615 item = this.findItemFromChild(e.getTarget());
48618 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
48619 this.contextMenu.showAt(e.getXY());
48624 * Remove {@link Roo.data.Record}s at the specified indices.
48625 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
48627 remove: function(selectedIndices) {
48628 selectedIndices = [].concat(selectedIndices);
48629 for (var i = 0; i < selectedIndices.length; i++) {
48630 var rec = this.store.getAt(selectedIndices[i]);
48631 this.store.remove(rec);
48636 * Double click fires the event, but also, if this is draggable, and there is only one other
48637 * related DropZone, it transfers the selected node.
48639 onDblClick : function(e){
48640 var item = this.findItemFromChild(e.getTarget());
48642 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
48645 if (this.dragGroup) {
48646 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
48647 while (targets.indexOf(this.dropZone) > -1) {
48648 targets.remove(this.dropZone);
48650 if (targets.length == 1) {
48651 this.dragZone.cachedTarget = null;
48652 var el = Roo.get(targets[0].getEl());
48653 var box = el.getBox(true);
48654 targets[0].onNodeDrop(el.dom, {
48656 xy: [box.x, box.y + box.height - 1]
48657 }, null, this.getDragData(e));
48663 handleSelection: function(e) {
48664 this.dragZone.cachedTarget = null;
48665 var item = this.findItemFromChild(e.getTarget());
48667 this.clearSelections(true);
48670 if (item && (this.multiSelect || this.singleSelect)){
48671 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
48672 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
48673 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
48674 this.unselect(item);
48676 this.select(item, this.multiSelect && e.ctrlKey);
48677 this.lastSelection = item;
48682 onItemClick : function(item, index, e){
48683 if(this.fireEvent("beforeclick", this, index, item, e) === false){
48689 unselect : function(nodeInfo, suppressEvent){
48690 var node = this.getNode(nodeInfo);
48691 if(node && this.isSelected(node)){
48692 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
48693 Roo.fly(node).removeClass(this.selectedClass);
48694 this.selections.remove(node);
48695 if(!suppressEvent){
48696 this.fireEvent("selectionchange", this, this.selections);
48704 * Ext JS Library 1.1.1
48705 * Copyright(c) 2006-2007, Ext JS, LLC.
48707 * Originally Released Under LGPL - original licence link has changed is not relivant.
48710 * <script type="text/javascript">
48714 * @class Roo.LayoutManager
48715 * @extends Roo.util.Observable
48716 * Base class for layout managers.
48718 Roo.LayoutManager = function(container, config){
48719 Roo.LayoutManager.superclass.constructor.call(this);
48720 this.el = Roo.get(container);
48721 // ie scrollbar fix
48722 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
48723 document.body.scroll = "no";
48724 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
48725 this.el.position('relative');
48727 this.id = this.el.id;
48728 this.el.addClass("x-layout-container");
48729 /** false to disable window resize monitoring @type Boolean */
48730 this.monitorWindowResize = true;
48735 * Fires when a layout is performed.
48736 * @param {Roo.LayoutManager} this
48740 * @event regionresized
48741 * Fires when the user resizes a region.
48742 * @param {Roo.LayoutRegion} region The resized region
48743 * @param {Number} newSize The new size (width for east/west, height for north/south)
48745 "regionresized" : true,
48747 * @event regioncollapsed
48748 * Fires when a region is collapsed.
48749 * @param {Roo.LayoutRegion} region The collapsed region
48751 "regioncollapsed" : true,
48753 * @event regionexpanded
48754 * Fires when a region is expanded.
48755 * @param {Roo.LayoutRegion} region The expanded region
48757 "regionexpanded" : true
48759 this.updating = false;
48760 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48763 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
48765 * Returns true if this layout is currently being updated
48766 * @return {Boolean}
48768 isUpdating : function(){
48769 return this.updating;
48773 * Suspend the LayoutManager from doing auto-layouts while
48774 * making multiple add or remove calls
48776 beginUpdate : function(){
48777 this.updating = true;
48781 * Restore auto-layouts and optionally disable the manager from performing a layout
48782 * @param {Boolean} noLayout true to disable a layout update
48784 endUpdate : function(noLayout){
48785 this.updating = false;
48791 layout: function(){
48795 onRegionResized : function(region, newSize){
48796 this.fireEvent("regionresized", region, newSize);
48800 onRegionCollapsed : function(region){
48801 this.fireEvent("regioncollapsed", region);
48804 onRegionExpanded : function(region){
48805 this.fireEvent("regionexpanded", region);
48809 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
48810 * performs box-model adjustments.
48811 * @return {Object} The size as an object {width: (the width), height: (the height)}
48813 getViewSize : function(){
48815 if(this.el.dom != document.body){
48816 size = this.el.getSize();
48818 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
48820 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
48821 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
48826 * Returns the Element this layout is bound to.
48827 * @return {Roo.Element}
48829 getEl : function(){
48834 * Returns the specified region.
48835 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
48836 * @return {Roo.LayoutRegion}
48838 getRegion : function(target){
48839 return this.regions[target.toLowerCase()];
48842 onWindowResize : function(){
48843 if(this.monitorWindowResize){
48849 * Ext JS Library 1.1.1
48850 * Copyright(c) 2006-2007, Ext JS, LLC.
48852 * Originally Released Under LGPL - original licence link has changed is not relivant.
48855 * <script type="text/javascript">
48858 * @class Roo.BorderLayout
48859 * @extends Roo.LayoutManager
48860 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
48861 * please see: <br><br>
48862 * <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>
48863 * <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>
48866 var layout = new Roo.BorderLayout(document.body, {
48900 preferredTabWidth: 150
48905 var CP = Roo.ContentPanel;
48907 layout.beginUpdate();
48908 layout.add("north", new CP("north", "North"));
48909 layout.add("south", new CP("south", {title: "South", closable: true}));
48910 layout.add("west", new CP("west", {title: "West"}));
48911 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
48912 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
48913 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
48914 layout.getRegion("center").showPanel("center1");
48915 layout.endUpdate();
48918 <b>The container the layout is rendered into can be either the body element or any other element.
48919 If it is not the body element, the container needs to either be an absolute positioned element,
48920 or you will need to add "position:relative" to the css of the container. You will also need to specify
48921 the container size if it is not the body element.</b>
48924 * Create a new BorderLayout
48925 * @param {String/HTMLElement/Element} container The container this layout is bound to
48926 * @param {Object} config Configuration options
48928 Roo.BorderLayout = function(container, config){
48929 config = config || {};
48930 Roo.BorderLayout.superclass.constructor.call(this, container, config);
48931 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
48932 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
48933 var target = this.factory.validRegions[i];
48934 if(config[target]){
48935 this.addRegion(target, config[target]);
48940 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
48942 * Creates and adds a new region if it doesn't already exist.
48943 * @param {String} target The target region key (north, south, east, west or center).
48944 * @param {Object} config The regions config object
48945 * @return {BorderLayoutRegion} The new region
48947 addRegion : function(target, config){
48948 if(!this.regions[target]){
48949 var r = this.factory.create(target, this, config);
48950 this.bindRegion(target, r);
48952 return this.regions[target];
48956 bindRegion : function(name, r){
48957 this.regions[name] = r;
48958 r.on("visibilitychange", this.layout, this);
48959 r.on("paneladded", this.layout, this);
48960 r.on("panelremoved", this.layout, this);
48961 r.on("invalidated", this.layout, this);
48962 r.on("resized", this.onRegionResized, this);
48963 r.on("collapsed", this.onRegionCollapsed, this);
48964 r.on("expanded", this.onRegionExpanded, this);
48968 * Performs a layout update.
48970 layout : function(){
48971 if(this.updating) return;
48972 var size = this.getViewSize();
48973 var w = size.width;
48974 var h = size.height;
48979 //var x = 0, y = 0;
48981 var rs = this.regions;
48982 var north = rs["north"];
48983 var south = rs["south"];
48984 var west = rs["west"];
48985 var east = rs["east"];
48986 var center = rs["center"];
48987 //if(this.hideOnLayout){ // not supported anymore
48988 //c.el.setStyle("display", "none");
48990 if(north && north.isVisible()){
48991 var b = north.getBox();
48992 var m = north.getMargins();
48993 b.width = w - (m.left+m.right);
48996 centerY = b.height + b.y + m.bottom;
48997 centerH -= centerY;
48998 north.updateBox(this.safeBox(b));
49000 if(south && south.isVisible()){
49001 var b = south.getBox();
49002 var m = south.getMargins();
49003 b.width = w - (m.left+m.right);
49005 var totalHeight = (b.height + m.top + m.bottom);
49006 b.y = h - totalHeight + m.top;
49007 centerH -= totalHeight;
49008 south.updateBox(this.safeBox(b));
49010 if(west && west.isVisible()){
49011 var b = west.getBox();
49012 var m = west.getMargins();
49013 b.height = centerH - (m.top+m.bottom);
49015 b.y = centerY + m.top;
49016 var totalWidth = (b.width + m.left + m.right);
49017 centerX += totalWidth;
49018 centerW -= totalWidth;
49019 west.updateBox(this.safeBox(b));
49021 if(east && east.isVisible()){
49022 var b = east.getBox();
49023 var m = east.getMargins();
49024 b.height = centerH - (m.top+m.bottom);
49025 var totalWidth = (b.width + m.left + m.right);
49026 b.x = w - totalWidth + m.left;
49027 b.y = centerY + m.top;
49028 centerW -= totalWidth;
49029 east.updateBox(this.safeBox(b));
49032 var m = center.getMargins();
49034 x: centerX + m.left,
49035 y: centerY + m.top,
49036 width: centerW - (m.left+m.right),
49037 height: centerH - (m.top+m.bottom)
49039 //if(this.hideOnLayout){
49040 //center.el.setStyle("display", "block");
49042 center.updateBox(this.safeBox(centerBox));
49045 this.fireEvent("layout", this);
49049 safeBox : function(box){
49050 box.width = Math.max(0, box.width);
49051 box.height = Math.max(0, box.height);
49056 * Adds a ContentPanel (or subclass) to this layout.
49057 * @param {String} target The target region key (north, south, east, west or center).
49058 * @param {Roo.ContentPanel} panel The panel to add
49059 * @return {Roo.ContentPanel} The added panel
49061 add : function(target, panel){
49063 target = target.toLowerCase();
49064 return this.regions[target].add(panel);
49068 * Remove a ContentPanel (or subclass) to this layout.
49069 * @param {String} target The target region key (north, south, east, west or center).
49070 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
49071 * @return {Roo.ContentPanel} The removed panel
49073 remove : function(target, panel){
49074 target = target.toLowerCase();
49075 return this.regions[target].remove(panel);
49079 * Searches all regions for a panel with the specified id
49080 * @param {String} panelId
49081 * @return {Roo.ContentPanel} The panel or null if it wasn't found
49083 findPanel : function(panelId){
49084 var rs = this.regions;
49085 for(var target in rs){
49086 if(typeof rs[target] != "function"){
49087 var p = rs[target].getPanel(panelId);
49097 * Searches all regions for a panel with the specified id and activates (shows) it.
49098 * @param {String/ContentPanel} panelId The panels id or the panel itself
49099 * @return {Roo.ContentPanel} The shown panel or null
49101 showPanel : function(panelId) {
49102 var rs = this.regions;
49103 for(var target in rs){
49104 var r = rs[target];
49105 if(typeof r != "function"){
49106 if(r.hasPanel(panelId)){
49107 return r.showPanel(panelId);
49115 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
49116 * @param {Roo.state.Provider} provider (optional) An alternate state provider
49118 restoreState : function(provider){
49120 provider = Roo.state.Manager;
49122 var sm = new Roo.LayoutStateManager();
49123 sm.init(this, provider);
49127 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
49128 * object should contain properties for each region to add ContentPanels to, and each property's value should be
49129 * a valid ContentPanel config object. Example:
49131 // Create the main layout
49132 var layout = new Roo.BorderLayout('main-ct', {
49143 // Create and add multiple ContentPanels at once via configs
49146 id: 'source-files',
49148 title:'Ext Source Files',
49161 * @param {Object} regions An object containing ContentPanel configs by region name
49163 batchAdd : function(regions){
49164 this.beginUpdate();
49165 for(var rname in regions){
49166 var lr = this.regions[rname];
49168 this.addTypedPanels(lr, regions[rname]);
49175 addTypedPanels : function(lr, ps){
49176 if(typeof ps == 'string'){
49177 lr.add(new Roo.ContentPanel(ps));
49179 else if(ps instanceof Array){
49180 for(var i =0, len = ps.length; i < len; i++){
49181 this.addTypedPanels(lr, ps[i]);
49184 else if(!ps.events){ // raw config?
49186 delete ps.el; // prevent conflict
49187 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49189 else { // panel object assumed!
49194 * Adds a xtype elements to the layout.
49198 xtype : 'ContentPanel',
49205 xtype : 'NestedLayoutPanel',
49211 items : [ ... list of content panels or nested layout panels.. ]
49215 * @param {Object} cfg Xtype definition of item to add.
49217 addxtype : function(cfg)
49219 // basically accepts a pannel...
49220 // can accept a layout region..!?!?
49221 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49223 if (!cfg.xtype.match(/Panel$/)) {
49228 if (typeof(cfg.region) == 'undefined') {
49229 Roo.log("Failed to add Panel, region was not set");
49233 var region = cfg.region;
49239 xitems = cfg.items;
49246 case 'ContentPanel': // ContentPanel (el, cfg)
49247 case 'ScrollPanel': // ContentPanel (el, cfg)
49249 if(cfg.autoCreate) {
49250 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49252 var el = this.el.createChild();
49253 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49256 this.add(region, ret);
49260 case 'TreePanel': // our new panel!
49261 cfg.el = this.el.createChild();
49262 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49263 this.add(region, ret);
49266 case 'NestedLayoutPanel':
49267 // create a new Layout (which is a Border Layout...
49268 var el = this.el.createChild();
49269 var clayout = cfg.layout;
49271 clayout.items = clayout.items || [];
49272 // replace this exitems with the clayout ones..
49273 xitems = clayout.items;
49276 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49277 cfg.background = false;
49279 var layout = new Roo.BorderLayout(el, clayout);
49281 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49282 //console.log('adding nested layout panel ' + cfg.toSource());
49283 this.add(region, ret);
49284 nb = {}; /// find first...
49289 // needs grid and region
49291 //var el = this.getRegion(region).el.createChild();
49292 var el = this.el.createChild();
49293 // create the grid first...
49295 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49297 if (region == 'center' && this.active ) {
49298 cfg.background = false;
49300 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49302 this.add(region, ret);
49303 if (cfg.background) {
49304 ret.on('activate', function(gp) {
49305 if (!gp.grid.rendered) {
49320 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49322 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49323 this.add(region, ret);
49326 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49330 // GridPanel (grid, cfg)
49333 this.beginUpdate();
49337 Roo.each(xitems, function(i) {
49338 region = nb && i.region ? i.region : false;
49340 var add = ret.addxtype(i);
49343 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49344 if (!i.background) {
49345 abn[region] = nb[region] ;
49352 // make the last non-background panel active..
49353 //if (nb) { Roo.log(abn); }
49356 for(var r in abn) {
49357 region = this.getRegion(r);
49359 // tried using nb[r], but it does not work..
49361 region.showPanel(abn[r]);
49372 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49373 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49374 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49375 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49378 var CP = Roo.ContentPanel;
49380 var layout = Roo.BorderLayout.create({
49384 panels: [new CP("north", "North")]
49393 panels: [new CP("west", {title: "West"})]
49402 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49411 panels: [new CP("south", {title: "South", closable: true})]
49418 preferredTabWidth: 150,
49420 new CP("center1", {title: "Close Me", closable: true}),
49421 new CP("center2", {title: "Center Panel", closable: false})
49426 layout.getRegion("center").showPanel("center1");
49431 Roo.BorderLayout.create = function(config, targetEl){
49432 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49433 layout.beginUpdate();
49434 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49435 for(var j = 0, jlen = regions.length; j < jlen; j++){
49436 var lr = regions[j];
49437 if(layout.regions[lr] && config[lr].panels){
49438 var r = layout.regions[lr];
49439 var ps = config[lr].panels;
49440 layout.addTypedPanels(r, ps);
49443 layout.endUpdate();
49448 Roo.BorderLayout.RegionFactory = {
49450 validRegions : ["north","south","east","west","center"],
49453 create : function(target, mgr, config){
49454 target = target.toLowerCase();
49455 if(config.lightweight || config.basic){
49456 return new Roo.BasicLayoutRegion(mgr, config, target);
49460 return new Roo.NorthLayoutRegion(mgr, config);
49462 return new Roo.SouthLayoutRegion(mgr, config);
49464 return new Roo.EastLayoutRegion(mgr, config);
49466 return new Roo.WestLayoutRegion(mgr, config);
49468 return new Roo.CenterLayoutRegion(mgr, config);
49470 throw 'Layout region "'+target+'" not supported.';
49474 * Ext JS Library 1.1.1
49475 * Copyright(c) 2006-2007, Ext JS, LLC.
49477 * Originally Released Under LGPL - original licence link has changed is not relivant.
49480 * <script type="text/javascript">
49484 * @class Roo.BasicLayoutRegion
49485 * @extends Roo.util.Observable
49486 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49487 * and does not have a titlebar, tabs or any other features. All it does is size and position
49488 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49490 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49492 this.position = pos;
49495 * @scope Roo.BasicLayoutRegion
49499 * @event beforeremove
49500 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49501 * @param {Roo.LayoutRegion} this
49502 * @param {Roo.ContentPanel} panel The panel
49503 * @param {Object} e The cancel event object
49505 "beforeremove" : true,
49507 * @event invalidated
49508 * Fires when the layout for this region is changed.
49509 * @param {Roo.LayoutRegion} this
49511 "invalidated" : true,
49513 * @event visibilitychange
49514 * Fires when this region is shown or hidden
49515 * @param {Roo.LayoutRegion} this
49516 * @param {Boolean} visibility true or false
49518 "visibilitychange" : true,
49520 * @event paneladded
49521 * Fires when a panel is added.
49522 * @param {Roo.LayoutRegion} this
49523 * @param {Roo.ContentPanel} panel The panel
49525 "paneladded" : true,
49527 * @event panelremoved
49528 * Fires when a panel is removed.
49529 * @param {Roo.LayoutRegion} this
49530 * @param {Roo.ContentPanel} panel The panel
49532 "panelremoved" : true,
49535 * Fires when this region is collapsed.
49536 * @param {Roo.LayoutRegion} this
49538 "collapsed" : true,
49541 * Fires when this region is expanded.
49542 * @param {Roo.LayoutRegion} this
49547 * Fires when this region is slid into view.
49548 * @param {Roo.LayoutRegion} this
49550 "slideshow" : true,
49553 * Fires when this region slides out of view.
49554 * @param {Roo.LayoutRegion} this
49556 "slidehide" : true,
49558 * @event panelactivated
49559 * Fires when a panel is activated.
49560 * @param {Roo.LayoutRegion} this
49561 * @param {Roo.ContentPanel} panel The activated panel
49563 "panelactivated" : true,
49566 * Fires when the user resizes this region.
49567 * @param {Roo.LayoutRegion} this
49568 * @param {Number} newSize The new size (width for east/west, height for north/south)
49572 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49573 this.panels = new Roo.util.MixedCollection();
49574 this.panels.getKey = this.getPanelId.createDelegate(this);
49576 this.activePanel = null;
49577 // ensure listeners are added...
49579 if (config.listeners || config.events) {
49580 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49581 listeners : config.listeners || {},
49582 events : config.events || {}
49586 if(skipConfig !== true){
49587 this.applyConfig(config);
49591 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49592 getPanelId : function(p){
49596 applyConfig : function(config){
49597 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49598 this.config = config;
49603 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49604 * the width, for horizontal (north, south) the height.
49605 * @param {Number} newSize The new width or height
49607 resizeTo : function(newSize){
49608 var el = this.el ? this.el :
49609 (this.activePanel ? this.activePanel.getEl() : null);
49611 switch(this.position){
49614 el.setWidth(newSize);
49615 this.fireEvent("resized", this, newSize);
49619 el.setHeight(newSize);
49620 this.fireEvent("resized", this, newSize);
49626 getBox : function(){
49627 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
49630 getMargins : function(){
49631 return this.margins;
49634 updateBox : function(box){
49636 var el = this.activePanel.getEl();
49637 el.dom.style.left = box.x + "px";
49638 el.dom.style.top = box.y + "px";
49639 this.activePanel.setSize(box.width, box.height);
49643 * Returns the container element for this region.
49644 * @return {Roo.Element}
49646 getEl : function(){
49647 return this.activePanel;
49651 * Returns true if this region is currently visible.
49652 * @return {Boolean}
49654 isVisible : function(){
49655 return this.activePanel ? true : false;
49658 setActivePanel : function(panel){
49659 panel = this.getPanel(panel);
49660 if(this.activePanel && this.activePanel != panel){
49661 this.activePanel.setActiveState(false);
49662 this.activePanel.getEl().setLeftTop(-10000,-10000);
49664 this.activePanel = panel;
49665 panel.setActiveState(true);
49667 panel.setSize(this.box.width, this.box.height);
49669 this.fireEvent("panelactivated", this, panel);
49670 this.fireEvent("invalidated");
49674 * Show the specified panel.
49675 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
49676 * @return {Roo.ContentPanel} The shown panel or null
49678 showPanel : function(panel){
49679 if(panel = this.getPanel(panel)){
49680 this.setActivePanel(panel);
49686 * Get the active panel for this region.
49687 * @return {Roo.ContentPanel} The active panel or null
49689 getActivePanel : function(){
49690 return this.activePanel;
49694 * Add the passed ContentPanel(s)
49695 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49696 * @return {Roo.ContentPanel} The panel added (if only one was added)
49698 add : function(panel){
49699 if(arguments.length > 1){
49700 for(var i = 0, len = arguments.length; i < len; i++) {
49701 this.add(arguments[i]);
49705 if(this.hasPanel(panel)){
49706 this.showPanel(panel);
49709 var el = panel.getEl();
49710 if(el.dom.parentNode != this.mgr.el.dom){
49711 this.mgr.el.dom.appendChild(el.dom);
49713 if(panel.setRegion){
49714 panel.setRegion(this);
49716 this.panels.add(panel);
49717 el.setStyle("position", "absolute");
49718 if(!panel.background){
49719 this.setActivePanel(panel);
49720 if(this.config.initialSize && this.panels.getCount()==1){
49721 this.resizeTo(this.config.initialSize);
49724 this.fireEvent("paneladded", this, panel);
49729 * Returns true if the panel is in this region.
49730 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49731 * @return {Boolean}
49733 hasPanel : function(panel){
49734 if(typeof panel == "object"){ // must be panel obj
49735 panel = panel.getId();
49737 return this.getPanel(panel) ? true : false;
49741 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49742 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49743 * @param {Boolean} preservePanel Overrides the config preservePanel option
49744 * @return {Roo.ContentPanel} The panel that was removed
49746 remove : function(panel, preservePanel){
49747 panel = this.getPanel(panel);
49752 this.fireEvent("beforeremove", this, panel, e);
49753 if(e.cancel === true){
49756 var panelId = panel.getId();
49757 this.panels.removeKey(panelId);
49762 * Returns the panel specified or null if it's not in this region.
49763 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49764 * @return {Roo.ContentPanel}
49766 getPanel : function(id){
49767 if(typeof id == "object"){ // must be panel obj
49770 return this.panels.get(id);
49774 * Returns this regions position (north/south/east/west/center).
49777 getPosition: function(){
49778 return this.position;
49782 * Ext JS Library 1.1.1
49783 * Copyright(c) 2006-2007, Ext JS, LLC.
49785 * Originally Released Under LGPL - original licence link has changed is not relivant.
49788 * <script type="text/javascript">
49792 * @class Roo.LayoutRegion
49793 * @extends Roo.BasicLayoutRegion
49794 * This class represents a region in a layout manager.
49795 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
49796 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
49797 * @cfg {Boolean} floatable False to disable floating (defaults to true)
49798 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
49799 * @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})
49800 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
49801 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
49802 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
49803 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
49804 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
49805 * @cfg {String} title The title for the region (overrides panel titles)
49806 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
49807 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
49808 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
49809 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
49810 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
49811 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
49812 * the space available, similar to FireFox 1.5 tabs (defaults to false)
49813 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
49814 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
49815 * @cfg {Boolean} showPin True to show a pin button
49816 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
49817 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
49818 * @cfg {Boolean} disableTabTips True to disable tab tooltips
49819 * @cfg {Number} width For East/West panels
49820 * @cfg {Number} height For North/South panels
49821 * @cfg {Boolean} split To show the splitter
49822 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
49824 Roo.LayoutRegion = function(mgr, config, pos){
49825 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
49826 var dh = Roo.DomHelper;
49827 /** This region's container element
49828 * @type Roo.Element */
49829 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
49830 /** This region's title element
49831 * @type Roo.Element */
49833 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
49834 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
49835 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
49837 this.titleEl.enableDisplayMode();
49838 /** This region's title text element
49839 * @type HTMLElement */
49840 this.titleTextEl = this.titleEl.dom.firstChild;
49841 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
49842 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
49843 this.closeBtn.enableDisplayMode();
49844 this.closeBtn.on("click", this.closeClicked, this);
49845 this.closeBtn.hide();
49847 this.createBody(config);
49848 this.visible = true;
49849 this.collapsed = false;
49851 if(config.hideWhenEmpty){
49853 this.on("paneladded", this.validateVisibility, this);
49854 this.on("panelremoved", this.validateVisibility, this);
49856 this.applyConfig(config);
49859 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
49861 createBody : function(){
49862 /** This region's body element
49863 * @type Roo.Element */
49864 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
49867 applyConfig : function(c){
49868 if(c.collapsible && this.position != "center" && !this.collapsedEl){
49869 var dh = Roo.DomHelper;
49870 if(c.titlebar !== false){
49871 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
49872 this.collapseBtn.on("click", this.collapse, this);
49873 this.collapseBtn.enableDisplayMode();
49875 if(c.showPin === true || this.showPin){
49876 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
49877 this.stickBtn.enableDisplayMode();
49878 this.stickBtn.on("click", this.expand, this);
49879 this.stickBtn.hide();
49882 /** This region's collapsed element
49883 * @type Roo.Element */
49884 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
49885 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
49887 if(c.floatable !== false){
49888 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
49889 this.collapsedEl.on("click", this.collapseClick, this);
49892 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
49893 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
49894 id: "message", unselectable: "on", style:{"float":"left"}});
49895 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
49897 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
49898 this.expandBtn.on("click", this.expand, this);
49900 if(this.collapseBtn){
49901 this.collapseBtn.setVisible(c.collapsible == true);
49903 this.cmargins = c.cmargins || this.cmargins ||
49904 (this.position == "west" || this.position == "east" ?
49905 {top: 0, left: 2, right:2, bottom: 0} :
49906 {top: 2, left: 0, right:0, bottom: 2});
49907 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49908 this.bottomTabs = c.tabPosition != "top";
49909 this.autoScroll = c.autoScroll || false;
49910 if(this.autoScroll){
49911 this.bodyEl.setStyle("overflow", "auto");
49913 this.bodyEl.setStyle("overflow", "hidden");
49915 //if(c.titlebar !== false){
49916 if((!c.titlebar && !c.title) || c.titlebar === false){
49917 this.titleEl.hide();
49919 this.titleEl.show();
49921 this.titleTextEl.innerHTML = c.title;
49925 this.duration = c.duration || .30;
49926 this.slideDuration = c.slideDuration || .45;
49929 this.collapse(true);
49936 * Returns true if this region is currently visible.
49937 * @return {Boolean}
49939 isVisible : function(){
49940 return this.visible;
49944 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
49945 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
49947 setCollapsedTitle : function(title){
49948 title = title || " ";
49949 if(this.collapsedTitleTextEl){
49950 this.collapsedTitleTextEl.innerHTML = title;
49954 getBox : function(){
49956 if(!this.collapsed){
49957 b = this.el.getBox(false, true);
49959 b = this.collapsedEl.getBox(false, true);
49964 getMargins : function(){
49965 return this.collapsed ? this.cmargins : this.margins;
49968 highlight : function(){
49969 this.el.addClass("x-layout-panel-dragover");
49972 unhighlight : function(){
49973 this.el.removeClass("x-layout-panel-dragover");
49976 updateBox : function(box){
49978 if(!this.collapsed){
49979 this.el.dom.style.left = box.x + "px";
49980 this.el.dom.style.top = box.y + "px";
49981 this.updateBody(box.width, box.height);
49983 this.collapsedEl.dom.style.left = box.x + "px";
49984 this.collapsedEl.dom.style.top = box.y + "px";
49985 this.collapsedEl.setSize(box.width, box.height);
49988 this.tabs.autoSizeTabs();
49992 updateBody : function(w, h){
49994 this.el.setWidth(w);
49995 w -= this.el.getBorderWidth("rl");
49996 if(this.config.adjustments){
49997 w += this.config.adjustments[0];
50001 this.el.setHeight(h);
50002 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
50003 h -= this.el.getBorderWidth("tb");
50004 if(this.config.adjustments){
50005 h += this.config.adjustments[1];
50007 this.bodyEl.setHeight(h);
50009 h = this.tabs.syncHeight(h);
50012 if(this.panelSize){
50013 w = w !== null ? w : this.panelSize.width;
50014 h = h !== null ? h : this.panelSize.height;
50016 if(this.activePanel){
50017 var el = this.activePanel.getEl();
50018 w = w !== null ? w : el.getWidth();
50019 h = h !== null ? h : el.getHeight();
50020 this.panelSize = {width: w, height: h};
50021 this.activePanel.setSize(w, h);
50023 if(Roo.isIE && this.tabs){
50024 this.tabs.el.repaint();
50029 * Returns the container element for this region.
50030 * @return {Roo.Element}
50032 getEl : function(){
50037 * Hides this region.
50040 if(!this.collapsed){
50041 this.el.dom.style.left = "-2000px";
50044 this.collapsedEl.dom.style.left = "-2000px";
50045 this.collapsedEl.hide();
50047 this.visible = false;
50048 this.fireEvent("visibilitychange", this, false);
50052 * Shows this region if it was previously hidden.
50055 if(!this.collapsed){
50058 this.collapsedEl.show();
50060 this.visible = true;
50061 this.fireEvent("visibilitychange", this, true);
50064 closeClicked : function(){
50065 if(this.activePanel){
50066 this.remove(this.activePanel);
50070 collapseClick : function(e){
50072 e.stopPropagation();
50075 e.stopPropagation();
50081 * Collapses this region.
50082 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
50084 collapse : function(skipAnim){
50085 if(this.collapsed) return;
50086 this.collapsed = true;
50088 this.split.el.hide();
50090 if(this.config.animate && skipAnim !== true){
50091 this.fireEvent("invalidated", this);
50092 this.animateCollapse();
50094 this.el.setLocation(-20000,-20000);
50096 this.collapsedEl.show();
50097 this.fireEvent("collapsed", this);
50098 this.fireEvent("invalidated", this);
50102 animateCollapse : function(){
50107 * Expands this region if it was previously collapsed.
50108 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
50109 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
50111 expand : function(e, skipAnim){
50112 if(e) e.stopPropagation();
50113 if(!this.collapsed || this.el.hasActiveFx()) return;
50115 this.afterSlideIn();
50118 this.collapsed = false;
50119 if(this.config.animate && skipAnim !== true){
50120 this.animateExpand();
50124 this.split.el.show();
50126 this.collapsedEl.setLocation(-2000,-2000);
50127 this.collapsedEl.hide();
50128 this.fireEvent("invalidated", this);
50129 this.fireEvent("expanded", this);
50133 animateExpand : function(){
50137 initTabs : function()
50139 this.bodyEl.setStyle("overflow", "hidden");
50140 var ts = new Roo.TabPanel(
50143 tabPosition: this.bottomTabs ? 'bottom' : 'top',
50144 disableTooltips: this.config.disableTabTips,
50145 toolbar : this.config.toolbar
50148 if(this.config.hideTabs){
50149 ts.stripWrap.setDisplayed(false);
50152 ts.resizeTabs = this.config.resizeTabs === true;
50153 ts.minTabWidth = this.config.minTabWidth || 40;
50154 ts.maxTabWidth = this.config.maxTabWidth || 250;
50155 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
50156 ts.monitorResize = false;
50157 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50158 ts.bodyEl.addClass('x-layout-tabs-body');
50159 this.panels.each(this.initPanelAsTab, this);
50162 initPanelAsTab : function(panel){
50163 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50164 this.config.closeOnTab && panel.isClosable());
50165 if(panel.tabTip !== undefined){
50166 ti.setTooltip(panel.tabTip);
50168 ti.on("activate", function(){
50169 this.setActivePanel(panel);
50171 if(this.config.closeOnTab){
50172 ti.on("beforeclose", function(t, e){
50174 this.remove(panel);
50180 updatePanelTitle : function(panel, title){
50181 if(this.activePanel == panel){
50182 this.updateTitle(title);
50185 var ti = this.tabs.getTab(panel.getEl().id);
50187 if(panel.tabTip !== undefined){
50188 ti.setTooltip(panel.tabTip);
50193 updateTitle : function(title){
50194 if(this.titleTextEl && !this.config.title){
50195 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50199 setActivePanel : function(panel){
50200 panel = this.getPanel(panel);
50201 if(this.activePanel && this.activePanel != panel){
50202 this.activePanel.setActiveState(false);
50204 this.activePanel = panel;
50205 panel.setActiveState(true);
50206 if(this.panelSize){
50207 panel.setSize(this.panelSize.width, this.panelSize.height);
50210 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50212 this.updateTitle(panel.getTitle());
50214 this.fireEvent("invalidated", this);
50216 this.fireEvent("panelactivated", this, panel);
50220 * Shows the specified panel.
50221 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50222 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50224 showPanel : function(panel){
50225 if(panel = this.getPanel(panel)){
50227 var tab = this.tabs.getTab(panel.getEl().id);
50228 if(tab.isHidden()){
50229 this.tabs.unhideTab(tab.id);
50233 this.setActivePanel(panel);
50240 * Get the active panel for this region.
50241 * @return {Roo.ContentPanel} The active panel or null
50243 getActivePanel : function(){
50244 return this.activePanel;
50247 validateVisibility : function(){
50248 if(this.panels.getCount() < 1){
50249 this.updateTitle(" ");
50250 this.closeBtn.hide();
50253 if(!this.isVisible()){
50260 * Adds the passed ContentPanel(s) to this region.
50261 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50262 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50264 add : function(panel){
50265 if(arguments.length > 1){
50266 for(var i = 0, len = arguments.length; i < len; i++) {
50267 this.add(arguments[i]);
50271 if(this.hasPanel(panel)){
50272 this.showPanel(panel);
50275 panel.setRegion(this);
50276 this.panels.add(panel);
50277 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50278 this.bodyEl.dom.appendChild(panel.getEl().dom);
50279 if(panel.background !== true){
50280 this.setActivePanel(panel);
50282 this.fireEvent("paneladded", this, panel);
50288 this.initPanelAsTab(panel);
50290 if(panel.background !== true){
50291 this.tabs.activate(panel.getEl().id);
50293 this.fireEvent("paneladded", this, panel);
50298 * Hides the tab for the specified panel.
50299 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50301 hidePanel : function(panel){
50302 if(this.tabs && (panel = this.getPanel(panel))){
50303 this.tabs.hideTab(panel.getEl().id);
50308 * Unhides the tab for a previously hidden panel.
50309 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50311 unhidePanel : function(panel){
50312 if(this.tabs && (panel = this.getPanel(panel))){
50313 this.tabs.unhideTab(panel.getEl().id);
50317 clearPanels : function(){
50318 while(this.panels.getCount() > 0){
50319 this.remove(this.panels.first());
50324 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50325 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50326 * @param {Boolean} preservePanel Overrides the config preservePanel option
50327 * @return {Roo.ContentPanel} The panel that was removed
50329 remove : function(panel, preservePanel){
50330 panel = this.getPanel(panel);
50335 this.fireEvent("beforeremove", this, panel, e);
50336 if(e.cancel === true){
50339 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50340 var panelId = panel.getId();
50341 this.panels.removeKey(panelId);
50343 document.body.appendChild(panel.getEl().dom);
50346 this.tabs.removeTab(panel.getEl().id);
50347 }else if (!preservePanel){
50348 this.bodyEl.dom.removeChild(panel.getEl().dom);
50350 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50351 var p = this.panels.first();
50352 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50353 tempEl.appendChild(p.getEl().dom);
50354 this.bodyEl.update("");
50355 this.bodyEl.dom.appendChild(p.getEl().dom);
50357 this.updateTitle(p.getTitle());
50359 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50360 this.setActivePanel(p);
50362 panel.setRegion(null);
50363 if(this.activePanel == panel){
50364 this.activePanel = null;
50366 if(this.config.autoDestroy !== false && preservePanel !== true){
50367 try{panel.destroy();}catch(e){}
50369 this.fireEvent("panelremoved", this, panel);
50374 * Returns the TabPanel component used by this region
50375 * @return {Roo.TabPanel}
50377 getTabs : function(){
50381 createTool : function(parentEl, className){
50382 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50383 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50384 btn.addClassOnOver("x-layout-tools-button-over");
50389 * Ext JS Library 1.1.1
50390 * Copyright(c) 2006-2007, Ext JS, LLC.
50392 * Originally Released Under LGPL - original licence link has changed is not relivant.
50395 * <script type="text/javascript">
50401 * @class Roo.SplitLayoutRegion
50402 * @extends Roo.LayoutRegion
50403 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50405 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50406 this.cursor = cursor;
50407 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50410 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50411 splitTip : "Drag to resize.",
50412 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50413 useSplitTips : false,
50415 applyConfig : function(config){
50416 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50419 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50420 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50421 /** The SplitBar for this region
50422 * @type Roo.SplitBar */
50423 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50424 this.split.on("moved", this.onSplitMove, this);
50425 this.split.useShim = config.useShim === true;
50426 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50427 if(this.useSplitTips){
50428 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50430 if(config.collapsible){
50431 this.split.el.on("dblclick", this.collapse, this);
50434 if(typeof config.minSize != "undefined"){
50435 this.split.minSize = config.minSize;
50437 if(typeof config.maxSize != "undefined"){
50438 this.split.maxSize = config.maxSize;
50440 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50441 this.hideSplitter();
50446 getHMaxSize : function(){
50447 var cmax = this.config.maxSize || 10000;
50448 var center = this.mgr.getRegion("center");
50449 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50452 getVMaxSize : function(){
50453 var cmax = this.config.maxSize || 10000;
50454 var center = this.mgr.getRegion("center");
50455 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50458 onSplitMove : function(split, newSize){
50459 this.fireEvent("resized", this, newSize);
50463 * Returns the {@link Roo.SplitBar} for this region.
50464 * @return {Roo.SplitBar}
50466 getSplitBar : function(){
50471 this.hideSplitter();
50472 Roo.SplitLayoutRegion.superclass.hide.call(this);
50475 hideSplitter : function(){
50477 this.split.el.setLocation(-2000,-2000);
50478 this.split.el.hide();
50484 this.split.el.show();
50486 Roo.SplitLayoutRegion.superclass.show.call(this);
50489 beforeSlide: function(){
50490 if(Roo.isGecko){// firefox overflow auto bug workaround
50491 this.bodyEl.clip();
50492 if(this.tabs) this.tabs.bodyEl.clip();
50493 if(this.activePanel){
50494 this.activePanel.getEl().clip();
50496 if(this.activePanel.beforeSlide){
50497 this.activePanel.beforeSlide();
50503 afterSlide : function(){
50504 if(Roo.isGecko){// firefox overflow auto bug workaround
50505 this.bodyEl.unclip();
50506 if(this.tabs) this.tabs.bodyEl.unclip();
50507 if(this.activePanel){
50508 this.activePanel.getEl().unclip();
50509 if(this.activePanel.afterSlide){
50510 this.activePanel.afterSlide();
50516 initAutoHide : function(){
50517 if(this.autoHide !== false){
50518 if(!this.autoHideHd){
50519 var st = new Roo.util.DelayedTask(this.slideIn, this);
50520 this.autoHideHd = {
50521 "mouseout": function(e){
50522 if(!e.within(this.el, true)){
50526 "mouseover" : function(e){
50532 this.el.on(this.autoHideHd);
50536 clearAutoHide : function(){
50537 if(this.autoHide !== false){
50538 this.el.un("mouseout", this.autoHideHd.mouseout);
50539 this.el.un("mouseover", this.autoHideHd.mouseover);
50543 clearMonitor : function(){
50544 Roo.get(document).un("click", this.slideInIf, this);
50547 // these names are backwards but not changed for compat
50548 slideOut : function(){
50549 if(this.isSlid || this.el.hasActiveFx()){
50552 this.isSlid = true;
50553 if(this.collapseBtn){
50554 this.collapseBtn.hide();
50556 this.closeBtnState = this.closeBtn.getStyle('display');
50557 this.closeBtn.hide();
50559 this.stickBtn.show();
50562 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50563 this.beforeSlide();
50564 this.el.setStyle("z-index", 10001);
50565 this.el.slideIn(this.getSlideAnchor(), {
50566 callback: function(){
50568 this.initAutoHide();
50569 Roo.get(document).on("click", this.slideInIf, this);
50570 this.fireEvent("slideshow", this);
50577 afterSlideIn : function(){
50578 this.clearAutoHide();
50579 this.isSlid = false;
50580 this.clearMonitor();
50581 this.el.setStyle("z-index", "");
50582 if(this.collapseBtn){
50583 this.collapseBtn.show();
50585 this.closeBtn.setStyle('display', this.closeBtnState);
50587 this.stickBtn.hide();
50589 this.fireEvent("slidehide", this);
50592 slideIn : function(cb){
50593 if(!this.isSlid || this.el.hasActiveFx()){
50597 this.isSlid = false;
50598 this.beforeSlide();
50599 this.el.slideOut(this.getSlideAnchor(), {
50600 callback: function(){
50601 this.el.setLeftTop(-10000, -10000);
50603 this.afterSlideIn();
50611 slideInIf : function(e){
50612 if(!e.within(this.el)){
50617 animateCollapse : function(){
50618 this.beforeSlide();
50619 this.el.setStyle("z-index", 20000);
50620 var anchor = this.getSlideAnchor();
50621 this.el.slideOut(anchor, {
50622 callback : function(){
50623 this.el.setStyle("z-index", "");
50624 this.collapsedEl.slideIn(anchor, {duration:.3});
50626 this.el.setLocation(-10000,-10000);
50628 this.fireEvent("collapsed", this);
50635 animateExpand : function(){
50636 this.beforeSlide();
50637 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
50638 this.el.setStyle("z-index", 20000);
50639 this.collapsedEl.hide({
50642 this.el.slideIn(this.getSlideAnchor(), {
50643 callback : function(){
50644 this.el.setStyle("z-index", "");
50647 this.split.el.show();
50649 this.fireEvent("invalidated", this);
50650 this.fireEvent("expanded", this);
50678 getAnchor : function(){
50679 return this.anchors[this.position];
50682 getCollapseAnchor : function(){
50683 return this.canchors[this.position];
50686 getSlideAnchor : function(){
50687 return this.sanchors[this.position];
50690 getAlignAdj : function(){
50691 var cm = this.cmargins;
50692 switch(this.position){
50708 getExpandAdj : function(){
50709 var c = this.collapsedEl, cm = this.cmargins;
50710 switch(this.position){
50712 return [-(cm.right+c.getWidth()+cm.left), 0];
50715 return [cm.right+c.getWidth()+cm.left, 0];
50718 return [0, -(cm.top+cm.bottom+c.getHeight())];
50721 return [0, cm.top+cm.bottom+c.getHeight()];
50727 * Ext JS Library 1.1.1
50728 * Copyright(c) 2006-2007, Ext JS, LLC.
50730 * Originally Released Under LGPL - original licence link has changed is not relivant.
50733 * <script type="text/javascript">
50736 * These classes are private internal classes
50738 Roo.CenterLayoutRegion = function(mgr, config){
50739 Roo.LayoutRegion.call(this, mgr, config, "center");
50740 this.visible = true;
50741 this.minWidth = config.minWidth || 20;
50742 this.minHeight = config.minHeight || 20;
50745 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
50747 // center panel can't be hidden
50751 // center panel can't be hidden
50754 getMinWidth: function(){
50755 return this.minWidth;
50758 getMinHeight: function(){
50759 return this.minHeight;
50764 Roo.NorthLayoutRegion = function(mgr, config){
50765 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
50767 this.split.placement = Roo.SplitBar.TOP;
50768 this.split.orientation = Roo.SplitBar.VERTICAL;
50769 this.split.el.addClass("x-layout-split-v");
50771 var size = config.initialSize || config.height;
50772 if(typeof size != "undefined"){
50773 this.el.setHeight(size);
50776 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
50777 orientation: Roo.SplitBar.VERTICAL,
50778 getBox : function(){
50779 if(this.collapsed){
50780 return this.collapsedEl.getBox();
50782 var box = this.el.getBox();
50784 box.height += this.split.el.getHeight();
50789 updateBox : function(box){
50790 if(this.split && !this.collapsed){
50791 box.height -= this.split.el.getHeight();
50792 this.split.el.setLeft(box.x);
50793 this.split.el.setTop(box.y+box.height);
50794 this.split.el.setWidth(box.width);
50796 if(this.collapsed){
50797 this.updateBody(box.width, null);
50799 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50803 Roo.SouthLayoutRegion = function(mgr, config){
50804 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
50806 this.split.placement = Roo.SplitBar.BOTTOM;
50807 this.split.orientation = Roo.SplitBar.VERTICAL;
50808 this.split.el.addClass("x-layout-split-v");
50810 var size = config.initialSize || config.height;
50811 if(typeof size != "undefined"){
50812 this.el.setHeight(size);
50815 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
50816 orientation: Roo.SplitBar.VERTICAL,
50817 getBox : function(){
50818 if(this.collapsed){
50819 return this.collapsedEl.getBox();
50821 var box = this.el.getBox();
50823 var sh = this.split.el.getHeight();
50830 updateBox : function(box){
50831 if(this.split && !this.collapsed){
50832 var sh = this.split.el.getHeight();
50835 this.split.el.setLeft(box.x);
50836 this.split.el.setTop(box.y-sh);
50837 this.split.el.setWidth(box.width);
50839 if(this.collapsed){
50840 this.updateBody(box.width, null);
50842 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50846 Roo.EastLayoutRegion = function(mgr, config){
50847 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
50849 this.split.placement = Roo.SplitBar.RIGHT;
50850 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50851 this.split.el.addClass("x-layout-split-h");
50853 var size = config.initialSize || config.width;
50854 if(typeof size != "undefined"){
50855 this.el.setWidth(size);
50858 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
50859 orientation: Roo.SplitBar.HORIZONTAL,
50860 getBox : function(){
50861 if(this.collapsed){
50862 return this.collapsedEl.getBox();
50864 var box = this.el.getBox();
50866 var sw = this.split.el.getWidth();
50873 updateBox : function(box){
50874 if(this.split && !this.collapsed){
50875 var sw = this.split.el.getWidth();
50877 this.split.el.setLeft(box.x);
50878 this.split.el.setTop(box.y);
50879 this.split.el.setHeight(box.height);
50882 if(this.collapsed){
50883 this.updateBody(null, box.height);
50885 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50889 Roo.WestLayoutRegion = function(mgr, config){
50890 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
50892 this.split.placement = Roo.SplitBar.LEFT;
50893 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50894 this.split.el.addClass("x-layout-split-h");
50896 var size = config.initialSize || config.width;
50897 if(typeof size != "undefined"){
50898 this.el.setWidth(size);
50901 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
50902 orientation: Roo.SplitBar.HORIZONTAL,
50903 getBox : function(){
50904 if(this.collapsed){
50905 return this.collapsedEl.getBox();
50907 var box = this.el.getBox();
50909 box.width += this.split.el.getWidth();
50914 updateBox : function(box){
50915 if(this.split && !this.collapsed){
50916 var sw = this.split.el.getWidth();
50918 this.split.el.setLeft(box.x+box.width);
50919 this.split.el.setTop(box.y);
50920 this.split.el.setHeight(box.height);
50922 if(this.collapsed){
50923 this.updateBody(null, box.height);
50925 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50930 * Ext JS Library 1.1.1
50931 * Copyright(c) 2006-2007, Ext JS, LLC.
50933 * Originally Released Under LGPL - original licence link has changed is not relivant.
50936 * <script type="text/javascript">
50941 * Private internal class for reading and applying state
50943 Roo.LayoutStateManager = function(layout){
50944 // default empty state
50953 Roo.LayoutStateManager.prototype = {
50954 init : function(layout, provider){
50955 this.provider = provider;
50956 var state = provider.get(layout.id+"-layout-state");
50958 var wasUpdating = layout.isUpdating();
50960 layout.beginUpdate();
50962 for(var key in state){
50963 if(typeof state[key] != "function"){
50964 var rstate = state[key];
50965 var r = layout.getRegion(key);
50968 r.resizeTo(rstate.size);
50970 if(rstate.collapsed == true){
50973 r.expand(null, true);
50979 layout.endUpdate();
50981 this.state = state;
50983 this.layout = layout;
50984 layout.on("regionresized", this.onRegionResized, this);
50985 layout.on("regioncollapsed", this.onRegionCollapsed, this);
50986 layout.on("regionexpanded", this.onRegionExpanded, this);
50989 storeState : function(){
50990 this.provider.set(this.layout.id+"-layout-state", this.state);
50993 onRegionResized : function(region, newSize){
50994 this.state[region.getPosition()].size = newSize;
50998 onRegionCollapsed : function(region){
50999 this.state[region.getPosition()].collapsed = true;
51003 onRegionExpanded : function(region){
51004 this.state[region.getPosition()].collapsed = false;
51009 * Ext JS Library 1.1.1
51010 * Copyright(c) 2006-2007, Ext JS, LLC.
51012 * Originally Released Under LGPL - original licence link has changed is not relivant.
51015 * <script type="text/javascript">
51018 * @class Roo.ContentPanel
51019 * @extends Roo.util.Observable
51020 * A basic ContentPanel element.
51021 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
51022 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
51023 * @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
51024 * @cfg {Boolean} closable True if the panel can be closed/removed
51025 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
51026 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
51027 * @cfg {Toolbar} toolbar A toolbar for this panel
51028 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
51029 * @cfg {String} title The title for this panel
51030 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
51031 * @cfg {String} url Calls {@link #setUrl} with this value
51032 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
51033 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
51034 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
51035 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
51038 * Create a new ContentPanel.
51039 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
51040 * @param {String/Object} config A string to set only the title or a config object
51041 * @param {String} content (optional) Set the HTML content for this panel
51042 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
51044 Roo.ContentPanel = function(el, config, content){
51048 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
51052 if (config && config.parentLayout) {
51053 el = config.parentLayout.el.createChild();
51056 if(el.autoCreate){ // xtype is available if this is called from factory
51060 this.el = Roo.get(el);
51061 if(!this.el && config && config.autoCreate){
51062 if(typeof config.autoCreate == "object"){
51063 if(!config.autoCreate.id){
51064 config.autoCreate.id = config.id||el;
51066 this.el = Roo.DomHelper.append(document.body,
51067 config.autoCreate, true);
51069 this.el = Roo.DomHelper.append(document.body,
51070 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
51073 this.closable = false;
51074 this.loaded = false;
51075 this.active = false;
51076 if(typeof config == "string"){
51077 this.title = config;
51079 Roo.apply(this, config);
51082 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
51083 this.wrapEl = this.el.wrap();
51084 this.toolbar.container = this.el.insertSibling(false, 'before');
51085 this.toolbar = new Roo.Toolbar(this.toolbar);
51088 // xtype created footer. - not sure if will work as we normally have to render first..
51089 if (this.footer && !this.footer.el && this.footer.xtype) {
51090 if (!this.wrapEl) {
51091 this.wrapEl = this.el.wrap();
51094 this.footer.container = this.wrapEl.createChild();
51096 this.footer = Roo.factory(this.footer, Roo);
51101 this.resizeEl = Roo.get(this.resizeEl, true);
51103 this.resizeEl = this.el;
51105 // handle view.xtype
51113 * Fires when this panel is activated.
51114 * @param {Roo.ContentPanel} this
51118 * @event deactivate
51119 * Fires when this panel is activated.
51120 * @param {Roo.ContentPanel} this
51122 "deactivate" : true,
51126 * Fires when this panel is resized if fitToFrame is true.
51127 * @param {Roo.ContentPanel} this
51128 * @param {Number} width The width after any component adjustments
51129 * @param {Number} height The height after any component adjustments
51135 * Fires when this tab is created
51136 * @param {Roo.ContentPanel} this
51147 if(this.autoScroll){
51148 this.resizeEl.setStyle("overflow", "auto");
51150 // fix randome scrolling
51151 this.el.on('scroll', function() {
51152 Roo.log('fix random scolling');
51153 this.scrollTo('top',0);
51156 content = content || this.content;
51158 this.setContent(content);
51160 if(config && config.url){
51161 this.setUrl(this.url, this.params, this.loadOnce);
51166 Roo.ContentPanel.superclass.constructor.call(this);
51168 if (this.view && typeof(this.view.xtype) != 'undefined') {
51169 this.view.el = this.el.appendChild(document.createElement("div"));
51170 this.view = Roo.factory(this.view);
51171 this.view.render && this.view.render(false, '');
51175 this.fireEvent('render', this);
51178 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51180 setRegion : function(region){
51181 this.region = region;
51183 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51185 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51190 * Returns the toolbar for this Panel if one was configured.
51191 * @return {Roo.Toolbar}
51193 getToolbar : function(){
51194 return this.toolbar;
51197 setActiveState : function(active){
51198 this.active = active;
51200 this.fireEvent("deactivate", this);
51202 this.fireEvent("activate", this);
51206 * Updates this panel's element
51207 * @param {String} content The new content
51208 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51210 setContent : function(content, loadScripts){
51211 this.el.update(content, loadScripts);
51214 ignoreResize : function(w, h){
51215 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51218 this.lastSize = {width: w, height: h};
51223 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51224 * @return {Roo.UpdateManager} The UpdateManager
51226 getUpdateManager : function(){
51227 return this.el.getUpdateManager();
51230 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51231 * @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:
51234 url: "your-url.php",
51235 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51236 callback: yourFunction,
51237 scope: yourObject, //(optional scope)
51240 text: "Loading...",
51245 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51246 * 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.
51247 * @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}
51248 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51249 * @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.
51250 * @return {Roo.ContentPanel} this
51253 var um = this.el.getUpdateManager();
51254 um.update.apply(um, arguments);
51260 * 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.
51261 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51262 * @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)
51263 * @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)
51264 * @return {Roo.UpdateManager} The UpdateManager
51266 setUrl : function(url, params, loadOnce){
51267 if(this.refreshDelegate){
51268 this.removeListener("activate", this.refreshDelegate);
51270 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51271 this.on("activate", this.refreshDelegate);
51272 return this.el.getUpdateManager();
51275 _handleRefresh : function(url, params, loadOnce){
51276 if(!loadOnce || !this.loaded){
51277 var updater = this.el.getUpdateManager();
51278 updater.update(url, params, this._setLoaded.createDelegate(this));
51282 _setLoaded : function(){
51283 this.loaded = true;
51287 * Returns this panel's id
51290 getId : function(){
51295 * Returns this panel's element - used by regiosn to add.
51296 * @return {Roo.Element}
51298 getEl : function(){
51299 return this.wrapEl || this.el;
51302 adjustForComponents : function(width, height)
51304 //Roo.log('adjustForComponents ');
51305 if(this.resizeEl != this.el){
51306 width -= this.el.getFrameWidth('lr');
51307 height -= this.el.getFrameWidth('tb');
51310 var te = this.toolbar.getEl();
51311 height -= te.getHeight();
51312 te.setWidth(width);
51315 var te = this.footer.getEl();
51316 Roo.log("footer:" + te.getHeight());
51318 height -= te.getHeight();
51319 te.setWidth(width);
51323 if(this.adjustments){
51324 width += this.adjustments[0];
51325 height += this.adjustments[1];
51327 return {"width": width, "height": height};
51330 setSize : function(width, height){
51331 if(this.fitToFrame && !this.ignoreResize(width, height)){
51332 if(this.fitContainer && this.resizeEl != this.el){
51333 this.el.setSize(width, height);
51335 var size = this.adjustForComponents(width, height);
51336 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51337 this.fireEvent('resize', this, size.width, size.height);
51342 * Returns this panel's title
51345 getTitle : function(){
51350 * Set this panel's title
51351 * @param {String} title
51353 setTitle : function(title){
51354 this.title = title;
51356 this.region.updatePanelTitle(this, title);
51361 * Returns true is this panel was configured to be closable
51362 * @return {Boolean}
51364 isClosable : function(){
51365 return this.closable;
51368 beforeSlide : function(){
51370 this.resizeEl.clip();
51373 afterSlide : function(){
51375 this.resizeEl.unclip();
51379 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51380 * Will fail silently if the {@link #setUrl} method has not been called.
51381 * This does not activate the panel, just updates its content.
51383 refresh : function(){
51384 if(this.refreshDelegate){
51385 this.loaded = false;
51386 this.refreshDelegate();
51391 * Destroys this panel
51393 destroy : function(){
51394 this.el.removeAllListeners();
51395 var tempEl = document.createElement("span");
51396 tempEl.appendChild(this.el.dom);
51397 tempEl.innerHTML = "";
51403 * form - if the content panel contains a form - this is a reference to it.
51404 * @type {Roo.form.Form}
51408 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51409 * This contains a reference to it.
51415 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51425 * @param {Object} cfg Xtype definition of item to add.
51428 addxtype : function(cfg) {
51430 if (cfg.xtype.match(/^Form$/)) {
51433 //if (this.footer) {
51434 // el = this.footer.container.insertSibling(false, 'before');
51436 el = this.el.createChild();
51439 this.form = new Roo.form.Form(cfg);
51442 if ( this.form.allItems.length) this.form.render(el.dom);
51445 // should only have one of theses..
51446 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51447 // views.. should not be just added - used named prop 'view''
51449 cfg.el = this.el.appendChild(document.createElement("div"));
51452 var ret = new Roo.factory(cfg);
51454 ret.render && ret.render(false, ''); // render blank..
51463 * @class Roo.GridPanel
51464 * @extends Roo.ContentPanel
51466 * Create a new GridPanel.
51467 * @param {Roo.grid.Grid} grid The grid for this panel
51468 * @param {String/Object} config A string to set only the panel's title, or a config object
51470 Roo.GridPanel = function(grid, config){
51473 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51474 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51476 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51478 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51481 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51483 // xtype created footer. - not sure if will work as we normally have to render first..
51484 if (this.footer && !this.footer.el && this.footer.xtype) {
51486 this.footer.container = this.grid.getView().getFooterPanel(true);
51487 this.footer.dataSource = this.grid.dataSource;
51488 this.footer = Roo.factory(this.footer, Roo);
51492 grid.monitorWindowResize = false; // turn off autosizing
51493 grid.autoHeight = false;
51494 grid.autoWidth = false;
51496 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51499 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51500 getId : function(){
51501 return this.grid.id;
51505 * Returns the grid for this panel
51506 * @return {Roo.grid.Grid}
51508 getGrid : function(){
51512 setSize : function(width, height){
51513 if(!this.ignoreResize(width, height)){
51514 var grid = this.grid;
51515 var size = this.adjustForComponents(width, height);
51516 grid.getGridEl().setSize(size.width, size.height);
51521 beforeSlide : function(){
51522 this.grid.getView().scroller.clip();
51525 afterSlide : function(){
51526 this.grid.getView().scroller.unclip();
51529 destroy : function(){
51530 this.grid.destroy();
51532 Roo.GridPanel.superclass.destroy.call(this);
51538 * @class Roo.NestedLayoutPanel
51539 * @extends Roo.ContentPanel
51541 * Create a new NestedLayoutPanel.
51544 * @param {Roo.BorderLayout} layout The layout for this panel
51545 * @param {String/Object} config A string to set only the title or a config object
51547 Roo.NestedLayoutPanel = function(layout, config)
51549 // construct with only one argument..
51550 /* FIXME - implement nicer consturctors
51551 if (layout.layout) {
51553 layout = config.layout;
51554 delete config.layout;
51556 if (layout.xtype && !layout.getEl) {
51557 // then layout needs constructing..
51558 layout = Roo.factory(layout, Roo);
51563 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51565 layout.monitorWindowResize = false; // turn off autosizing
51566 this.layout = layout;
51567 this.layout.getEl().addClass("x-layout-nested-layout");
51574 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51576 setSize : function(width, height){
51577 if(!this.ignoreResize(width, height)){
51578 var size = this.adjustForComponents(width, height);
51579 var el = this.layout.getEl();
51580 el.setSize(size.width, size.height);
51581 var touch = el.dom.offsetWidth;
51582 this.layout.layout();
51583 // ie requires a double layout on the first pass
51584 if(Roo.isIE && !this.initialized){
51585 this.initialized = true;
51586 this.layout.layout();
51591 // activate all subpanels if not currently active..
51593 setActiveState : function(active){
51594 this.active = active;
51596 this.fireEvent("deactivate", this);
51600 this.fireEvent("activate", this);
51601 // not sure if this should happen before or after..
51602 if (!this.layout) {
51603 return; // should not happen..
51606 for (var r in this.layout.regions) {
51607 reg = this.layout.getRegion(r);
51608 if (reg.getActivePanel()) {
51609 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51610 reg.setActivePanel(reg.getActivePanel());
51613 if (!reg.panels.length) {
51616 reg.showPanel(reg.getPanel(0));
51625 * Returns the nested BorderLayout for this panel
51626 * @return {Roo.BorderLayout}
51628 getLayout : function(){
51629 return this.layout;
51633 * Adds a xtype elements to the layout of the nested panel
51637 xtype : 'ContentPanel',
51644 xtype : 'NestedLayoutPanel',
51650 items : [ ... list of content panels or nested layout panels.. ]
51654 * @param {Object} cfg Xtype definition of item to add.
51656 addxtype : function(cfg) {
51657 return this.layout.addxtype(cfg);
51662 Roo.ScrollPanel = function(el, config, content){
51663 config = config || {};
51664 config.fitToFrame = true;
51665 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
51667 this.el.dom.style.overflow = "hidden";
51668 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
51669 this.el.removeClass("x-layout-inactive-content");
51670 this.el.on("mousewheel", this.onWheel, this);
51672 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
51673 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
51674 up.unselectable(); down.unselectable();
51675 up.on("click", this.scrollUp, this);
51676 down.on("click", this.scrollDown, this);
51677 up.addClassOnOver("x-scroller-btn-over");
51678 down.addClassOnOver("x-scroller-btn-over");
51679 up.addClassOnClick("x-scroller-btn-click");
51680 down.addClassOnClick("x-scroller-btn-click");
51681 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
51683 this.resizeEl = this.el;
51684 this.el = wrap; this.up = up; this.down = down;
51687 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
51689 wheelIncrement : 5,
51690 scrollUp : function(){
51691 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
51694 scrollDown : function(){
51695 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
51698 afterScroll : function(){
51699 var el = this.resizeEl;
51700 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
51701 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51702 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51705 setSize : function(){
51706 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
51707 this.afterScroll();
51710 onWheel : function(e){
51711 var d = e.getWheelDelta();
51712 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
51713 this.afterScroll();
51717 setContent : function(content, loadScripts){
51718 this.resizeEl.update(content, loadScripts);
51732 * @class Roo.TreePanel
51733 * @extends Roo.ContentPanel
51735 * Create a new TreePanel. - defaults to fit/scoll contents.
51736 * @param {String/Object} config A string to set only the panel's title, or a config object
51737 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
51739 Roo.TreePanel = function(config){
51740 var el = config.el;
51741 var tree = config.tree;
51742 delete config.tree;
51743 delete config.el; // hopefull!
51745 // wrapper for IE7 strict & safari scroll issue
51747 var treeEl = el.createChild();
51748 config.resizeEl = treeEl;
51752 Roo.TreePanel.superclass.constructor.call(this, el, config);
51755 this.tree = new Roo.tree.TreePanel(treeEl , tree);
51756 //console.log(tree);
51757 this.on('activate', function()
51759 if (this.tree.rendered) {
51762 //console.log('render tree');
51763 this.tree.render();
51765 // this should not be needed.. - it's actually the 'el' that resizes?
51766 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
51768 //this.on('resize', function (cp, w, h) {
51769 // this.tree.innerCt.setWidth(w);
51770 // this.tree.innerCt.setHeight(h);
51771 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
51778 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
51795 * Ext JS Library 1.1.1
51796 * Copyright(c) 2006-2007, Ext JS, LLC.
51798 * Originally Released Under LGPL - original licence link has changed is not relivant.
51801 * <script type="text/javascript">
51806 * @class Roo.ReaderLayout
51807 * @extends Roo.BorderLayout
51808 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
51809 * center region containing two nested regions (a top one for a list view and one for item preview below),
51810 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
51811 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
51812 * expedites the setup of the overall layout and regions for this common application style.
51815 var reader = new Roo.ReaderLayout();
51816 var CP = Roo.ContentPanel; // shortcut for adding
51818 reader.beginUpdate();
51819 reader.add("north", new CP("north", "North"));
51820 reader.add("west", new CP("west", {title: "West"}));
51821 reader.add("east", new CP("east", {title: "East"}));
51823 reader.regions.listView.add(new CP("listView", "List"));
51824 reader.regions.preview.add(new CP("preview", "Preview"));
51825 reader.endUpdate();
51828 * Create a new ReaderLayout
51829 * @param {Object} config Configuration options
51830 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
51831 * document.body if omitted)
51833 Roo.ReaderLayout = function(config, renderTo){
51834 var c = config || {size:{}};
51835 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
51836 north: c.north !== false ? Roo.apply({
51840 }, c.north) : false,
51841 west: c.west !== false ? Roo.apply({
51849 margins:{left:5,right:0,bottom:5,top:5},
51850 cmargins:{left:5,right:5,bottom:5,top:5}
51851 }, c.west) : false,
51852 east: c.east !== false ? Roo.apply({
51860 margins:{left:0,right:5,bottom:5,top:5},
51861 cmargins:{left:5,right:5,bottom:5,top:5}
51862 }, c.east) : false,
51863 center: Roo.apply({
51864 tabPosition: 'top',
51868 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
51872 this.el.addClass('x-reader');
51874 this.beginUpdate();
51876 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
51877 south: c.preview !== false ? Roo.apply({
51884 cmargins:{top:5,left:0, right:0, bottom:0}
51885 }, c.preview) : false,
51886 center: Roo.apply({
51892 this.add('center', new Roo.NestedLayoutPanel(inner,
51893 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
51897 this.regions.preview = inner.getRegion('south');
51898 this.regions.listView = inner.getRegion('center');
51901 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
51903 * Ext JS Library 1.1.1
51904 * Copyright(c) 2006-2007, Ext JS, LLC.
51906 * Originally Released Under LGPL - original licence link has changed is not relivant.
51909 * <script type="text/javascript">
51913 * @class Roo.grid.Grid
51914 * @extends Roo.util.Observable
51915 * This class represents the primary interface of a component based grid control.
51916 * <br><br>Usage:<pre><code>
51917 var grid = new Roo.grid.Grid("my-container-id", {
51920 selModel: mySelectionModel,
51921 autoSizeColumns: true,
51922 monitorWindowResize: false,
51923 trackMouseOver: true
51928 * <b>Common Problems:</b><br/>
51929 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
51930 * element will correct this<br/>
51931 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
51932 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
51933 * are unpredictable.<br/>
51934 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
51935 * grid to calculate dimensions/offsets.<br/>
51937 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51938 * The container MUST have some type of size defined for the grid to fill. The container will be
51939 * automatically set to position relative if it isn't already.
51940 * @param {Object} config A config object that sets properties on this grid.
51942 Roo.grid.Grid = function(container, config){
51943 // initialize the container
51944 this.container = Roo.get(container);
51945 this.container.update("");
51946 this.container.setStyle("overflow", "hidden");
51947 this.container.addClass('x-grid-container');
51949 this.id = this.container.id;
51951 Roo.apply(this, config);
51952 // check and correct shorthanded configs
51954 this.dataSource = this.ds;
51958 this.colModel = this.cm;
51962 this.selModel = this.sm;
51966 if (this.selModel) {
51967 this.selModel = Roo.factory(this.selModel, Roo.grid);
51968 this.sm = this.selModel;
51969 this.sm.xmodule = this.xmodule || false;
51971 if (typeof(this.colModel.config) == 'undefined') {
51972 this.colModel = new Roo.grid.ColumnModel(this.colModel);
51973 this.cm = this.colModel;
51974 this.cm.xmodule = this.xmodule || false;
51976 if (this.dataSource) {
51977 this.dataSource= Roo.factory(this.dataSource, Roo.data);
51978 this.ds = this.dataSource;
51979 this.ds.xmodule = this.xmodule || false;
51986 this.container.setWidth(this.width);
51990 this.container.setHeight(this.height);
51997 * The raw click event for the entire grid.
51998 * @param {Roo.EventObject} e
52003 * The raw dblclick event for the entire grid.
52004 * @param {Roo.EventObject} e
52008 * @event contextmenu
52009 * The raw contextmenu event for the entire grid.
52010 * @param {Roo.EventObject} e
52012 "contextmenu" : true,
52015 * The raw mousedown event for the entire grid.
52016 * @param {Roo.EventObject} e
52018 "mousedown" : true,
52021 * The raw mouseup event for the entire grid.
52022 * @param {Roo.EventObject} e
52027 * The raw mouseover event for the entire grid.
52028 * @param {Roo.EventObject} e
52030 "mouseover" : true,
52033 * The raw mouseout event for the entire grid.
52034 * @param {Roo.EventObject} e
52039 * The raw keypress event for the entire grid.
52040 * @param {Roo.EventObject} e
52045 * The raw keydown event for the entire grid.
52046 * @param {Roo.EventObject} e
52054 * Fires when a cell is clicked
52055 * @param {Grid} this
52056 * @param {Number} rowIndex
52057 * @param {Number} columnIndex
52058 * @param {Roo.EventObject} e
52060 "cellclick" : true,
52062 * @event celldblclick
52063 * Fires when a cell is double clicked
52064 * @param {Grid} this
52065 * @param {Number} rowIndex
52066 * @param {Number} columnIndex
52067 * @param {Roo.EventObject} e
52069 "celldblclick" : true,
52072 * Fires when a row is clicked
52073 * @param {Grid} this
52074 * @param {Number} rowIndex
52075 * @param {Roo.EventObject} e
52079 * @event rowdblclick
52080 * Fires when a row is double clicked
52081 * @param {Grid} this
52082 * @param {Number} rowIndex
52083 * @param {Roo.EventObject} e
52085 "rowdblclick" : true,
52087 * @event headerclick
52088 * Fires when a header is clicked
52089 * @param {Grid} this
52090 * @param {Number} columnIndex
52091 * @param {Roo.EventObject} e
52093 "headerclick" : true,
52095 * @event headerdblclick
52096 * Fires when a header cell is double clicked
52097 * @param {Grid} this
52098 * @param {Number} columnIndex
52099 * @param {Roo.EventObject} e
52101 "headerdblclick" : true,
52103 * @event rowcontextmenu
52104 * Fires when a row is right clicked
52105 * @param {Grid} this
52106 * @param {Number} rowIndex
52107 * @param {Roo.EventObject} e
52109 "rowcontextmenu" : true,
52111 * @event cellcontextmenu
52112 * Fires when a cell is right clicked
52113 * @param {Grid} this
52114 * @param {Number} rowIndex
52115 * @param {Number} cellIndex
52116 * @param {Roo.EventObject} e
52118 "cellcontextmenu" : true,
52120 * @event headercontextmenu
52121 * Fires when a header is right clicked
52122 * @param {Grid} this
52123 * @param {Number} columnIndex
52124 * @param {Roo.EventObject} e
52126 "headercontextmenu" : true,
52128 * @event bodyscroll
52129 * Fires when the body element is scrolled
52130 * @param {Number} scrollLeft
52131 * @param {Number} scrollTop
52133 "bodyscroll" : true,
52135 * @event columnresize
52136 * Fires when the user resizes a column
52137 * @param {Number} columnIndex
52138 * @param {Number} newSize
52140 "columnresize" : true,
52142 * @event columnmove
52143 * Fires when the user moves a column
52144 * @param {Number} oldIndex
52145 * @param {Number} newIndex
52147 "columnmove" : true,
52150 * Fires when row(s) start being dragged
52151 * @param {Grid} this
52152 * @param {Roo.GridDD} dd The drag drop object
52153 * @param {event} e The raw browser event
52155 "startdrag" : true,
52158 * Fires when a drag operation is complete
52159 * @param {Grid} this
52160 * @param {Roo.GridDD} dd The drag drop object
52161 * @param {event} e The raw browser event
52166 * Fires when dragged row(s) are dropped on a valid DD target
52167 * @param {Grid} this
52168 * @param {Roo.GridDD} dd The drag drop object
52169 * @param {String} targetId The target drag drop object
52170 * @param {event} e The raw browser event
52175 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52176 * @param {Grid} this
52177 * @param {Roo.GridDD} dd The drag drop object
52178 * @param {String} targetId The target drag drop object
52179 * @param {event} e The raw browser event
52184 * Fires when the dragged row(s) first cross another DD target while being dragged
52185 * @param {Grid} this
52186 * @param {Roo.GridDD} dd The drag drop object
52187 * @param {String} targetId The target drag drop object
52188 * @param {event} e The raw browser event
52190 "dragenter" : true,
52193 * Fires when the dragged row(s) leave another DD target while being dragged
52194 * @param {Grid} this
52195 * @param {Roo.GridDD} dd The drag drop object
52196 * @param {String} targetId The target drag drop object
52197 * @param {event} e The raw browser event
52202 * Fires when a row is rendered, so you can change add a style to it.
52203 * @param {GridView} gridview The grid view
52204 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52210 * Fires when the grid is rendered
52211 * @param {Grid} grid
52216 Roo.grid.Grid.superclass.constructor.call(this);
52218 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52221 * @cfg {String} ddGroup - drag drop group.
52225 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52227 minColumnWidth : 25,
52230 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52231 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52232 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52234 autoSizeColumns : false,
52237 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52239 autoSizeHeaders : true,
52242 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52244 monitorWindowResize : true,
52247 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52248 * rows measured to get a columns size. Default is 0 (all rows).
52250 maxRowsToMeasure : 0,
52253 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52255 trackMouseOver : true,
52258 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52262 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52264 enableDragDrop : false,
52267 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52269 enableColumnMove : true,
52272 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52274 enableColumnHide : true,
52277 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52279 enableRowHeightSync : false,
52282 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52287 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52289 autoHeight : false,
52292 * @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.
52294 autoExpandColumn : false,
52297 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52300 autoExpandMin : 50,
52303 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52305 autoExpandMax : 1000,
52308 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52313 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52317 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52327 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52328 * of a fixed width. Default is false.
52331 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52334 * Called once after all setup has been completed and the grid is ready to be rendered.
52335 * @return {Roo.grid.Grid} this
52337 render : function()
52339 var c = this.container;
52340 // try to detect autoHeight/width mode
52341 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52342 this.autoHeight = true;
52344 var view = this.getView();
52347 c.on("click", this.onClick, this);
52348 c.on("dblclick", this.onDblClick, this);
52349 c.on("contextmenu", this.onContextMenu, this);
52350 c.on("keydown", this.onKeyDown, this);
52352 c.on("touchstart", this.onTouchStart, this);
52355 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52357 this.getSelectionModel().init(this);
52362 this.loadMask = new Roo.LoadMask(this.container,
52363 Roo.apply({store:this.dataSource}, this.loadMask));
52367 if (this.toolbar && this.toolbar.xtype) {
52368 this.toolbar.container = this.getView().getHeaderPanel(true);
52369 this.toolbar = new Roo.Toolbar(this.toolbar);
52371 if (this.footer && this.footer.xtype) {
52372 this.footer.dataSource = this.getDataSource();
52373 this.footer.container = this.getView().getFooterPanel(true);
52374 this.footer = Roo.factory(this.footer, Roo);
52376 if (this.dropTarget && this.dropTarget.xtype) {
52377 delete this.dropTarget.xtype;
52378 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52382 this.rendered = true;
52383 this.fireEvent('render', this);
52388 * Reconfigures the grid to use a different Store and Column Model.
52389 * The View will be bound to the new objects and refreshed.
52390 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52391 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52393 reconfigure : function(dataSource, colModel){
52395 this.loadMask.destroy();
52396 this.loadMask = new Roo.LoadMask(this.container,
52397 Roo.apply({store:dataSource}, this.loadMask));
52399 this.view.bind(dataSource, colModel);
52400 this.dataSource = dataSource;
52401 this.colModel = colModel;
52402 this.view.refresh(true);
52406 onKeyDown : function(e){
52407 this.fireEvent("keydown", e);
52411 * Destroy this grid.
52412 * @param {Boolean} removeEl True to remove the element
52414 destroy : function(removeEl, keepListeners){
52416 this.loadMask.destroy();
52418 var c = this.container;
52419 c.removeAllListeners();
52420 this.view.destroy();
52421 this.colModel.purgeListeners();
52422 if(!keepListeners){
52423 this.purgeListeners();
52426 if(removeEl === true){
52432 processEvent : function(name, e){
52433 // does this fire select???
52434 Roo.log('grid:processEvent ' + name);
52436 if (name != 'touchstart' ) {
52437 this.fireEvent(name, e);
52440 var t = e.getTarget();
52442 var header = v.findHeaderIndex(t);
52443 if(header !== false){
52444 var ename = name == 'touchstart' ? 'click' : name;
52446 this.fireEvent("header" + ename, this, header, e);
52448 var row = v.findRowIndex(t);
52449 var cell = v.findCellIndex(t);
52450 if (name == 'touchstart') {
52451 // first touch is always a click.
52452 // hopefull this happens after selection is updated.?
52455 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52456 var cs = this.selModel.getSelectedCell();
52457 if (row == cs[0] && cell == cs[1]){
52461 if (typeof(this.selModel.getSelections) != 'undefined') {
52462 var cs = this.selModel.getSelections();
52463 var ds = this.dataSource;
52464 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52475 this.fireEvent("row" + name, this, row, e);
52476 if(cell !== false){
52477 this.fireEvent("cell" + name, this, row, cell, e);
52484 onClick : function(e){
52485 this.processEvent("click", e);
52488 onTouchStart : function(e){
52489 this.processEvent("touchstart", e);
52493 onContextMenu : function(e, t){
52494 this.processEvent("contextmenu", e);
52498 onDblClick : function(e){
52499 this.processEvent("dblclick", e);
52503 walkCells : function(row, col, step, fn, scope){
52504 var cm = this.colModel, clen = cm.getColumnCount();
52505 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52517 if(fn.call(scope || this, row, col, cm) === true){
52535 if(fn.call(scope || this, row, col, cm) === true){
52547 getSelections : function(){
52548 return this.selModel.getSelections();
52552 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52553 * but if manual update is required this method will initiate it.
52555 autoSize : function(){
52557 this.view.layout();
52558 if(this.view.adjustForScroll){
52559 this.view.adjustForScroll();
52565 * Returns the grid's underlying element.
52566 * @return {Element} The element
52568 getGridEl : function(){
52569 return this.container;
52572 // private for compatibility, overridden by editor grid
52573 stopEditing : function(){},
52576 * Returns the grid's SelectionModel.
52577 * @return {SelectionModel}
52579 getSelectionModel : function(){
52580 if(!this.selModel){
52581 this.selModel = new Roo.grid.RowSelectionModel();
52583 return this.selModel;
52587 * Returns the grid's DataSource.
52588 * @return {DataSource}
52590 getDataSource : function(){
52591 return this.dataSource;
52595 * Returns the grid's ColumnModel.
52596 * @return {ColumnModel}
52598 getColumnModel : function(){
52599 return this.colModel;
52603 * Returns the grid's GridView object.
52604 * @return {GridView}
52606 getView : function(){
52608 this.view = new Roo.grid.GridView(this.viewConfig);
52613 * Called to get grid's drag proxy text, by default returns this.ddText.
52616 getDragDropText : function(){
52617 var count = this.selModel.getCount();
52618 return String.format(this.ddText, count, count == 1 ? '' : 's');
52622 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
52623 * %0 is replaced with the number of selected rows.
52626 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
52628 * Ext JS Library 1.1.1
52629 * Copyright(c) 2006-2007, Ext JS, LLC.
52631 * Originally Released Under LGPL - original licence link has changed is not relivant.
52634 * <script type="text/javascript">
52637 Roo.grid.AbstractGridView = function(){
52641 "beforerowremoved" : true,
52642 "beforerowsinserted" : true,
52643 "beforerefresh" : true,
52644 "rowremoved" : true,
52645 "rowsinserted" : true,
52646 "rowupdated" : true,
52649 Roo.grid.AbstractGridView.superclass.constructor.call(this);
52652 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
52653 rowClass : "x-grid-row",
52654 cellClass : "x-grid-cell",
52655 tdClass : "x-grid-td",
52656 hdClass : "x-grid-hd",
52657 splitClass : "x-grid-hd-split",
52659 init: function(grid){
52661 var cid = this.grid.getGridEl().id;
52662 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
52663 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
52664 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
52665 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
52668 getColumnRenderers : function(){
52669 var renderers = [];
52670 var cm = this.grid.colModel;
52671 var colCount = cm.getColumnCount();
52672 for(var i = 0; i < colCount; i++){
52673 renderers[i] = cm.getRenderer(i);
52678 getColumnIds : function(){
52680 var cm = this.grid.colModel;
52681 var colCount = cm.getColumnCount();
52682 for(var i = 0; i < colCount; i++){
52683 ids[i] = cm.getColumnId(i);
52688 getDataIndexes : function(){
52689 if(!this.indexMap){
52690 this.indexMap = this.buildIndexMap();
52692 return this.indexMap.colToData;
52695 getColumnIndexByDataIndex : function(dataIndex){
52696 if(!this.indexMap){
52697 this.indexMap = this.buildIndexMap();
52699 return this.indexMap.dataToCol[dataIndex];
52703 * Set a css style for a column dynamically.
52704 * @param {Number} colIndex The index of the column
52705 * @param {String} name The css property name
52706 * @param {String} value The css value
52708 setCSSStyle : function(colIndex, name, value){
52709 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
52710 Roo.util.CSS.updateRule(selector, name, value);
52713 generateRules : function(cm){
52714 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
52715 Roo.util.CSS.removeStyleSheet(rulesId);
52716 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52717 var cid = cm.getColumnId(i);
52718 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
52719 this.tdSelector, cid, " {\n}\n",
52720 this.hdSelector, cid, " {\n}\n",
52721 this.splitSelector, cid, " {\n}\n");
52723 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52727 * Ext JS Library 1.1.1
52728 * Copyright(c) 2006-2007, Ext JS, LLC.
52730 * Originally Released Under LGPL - original licence link has changed is not relivant.
52733 * <script type="text/javascript">
52737 // This is a support class used internally by the Grid components
52738 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
52740 this.view = grid.getView();
52741 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52742 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
52744 this.setHandleElId(Roo.id(hd));
52745 this.setOuterHandleElId(Roo.id(hd2));
52747 this.scroll = false;
52749 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
52751 getDragData : function(e){
52752 var t = Roo.lib.Event.getTarget(e);
52753 var h = this.view.findHeaderCell(t);
52755 return {ddel: h.firstChild, header:h};
52760 onInitDrag : function(e){
52761 this.view.headersDisabled = true;
52762 var clone = this.dragData.ddel.cloneNode(true);
52763 clone.id = Roo.id();
52764 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
52765 this.proxy.update(clone);
52769 afterValidDrop : function(){
52771 setTimeout(function(){
52772 v.headersDisabled = false;
52776 afterInvalidDrop : function(){
52778 setTimeout(function(){
52779 v.headersDisabled = false;
52785 * Ext JS Library 1.1.1
52786 * Copyright(c) 2006-2007, Ext JS, LLC.
52788 * Originally Released Under LGPL - original licence link has changed is not relivant.
52791 * <script type="text/javascript">
52794 // This is a support class used internally by the Grid components
52795 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
52797 this.view = grid.getView();
52798 // split the proxies so they don't interfere with mouse events
52799 this.proxyTop = Roo.DomHelper.append(document.body, {
52800 cls:"col-move-top", html:" "
52802 this.proxyBottom = Roo.DomHelper.append(document.body, {
52803 cls:"col-move-bottom", html:" "
52805 this.proxyTop.hide = this.proxyBottom.hide = function(){
52806 this.setLeftTop(-100,-100);
52807 this.setStyle("visibility", "hidden");
52809 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52810 // temporarily disabled
52811 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
52812 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
52814 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
52815 proxyOffsets : [-4, -9],
52816 fly: Roo.Element.fly,
52818 getTargetFromEvent : function(e){
52819 var t = Roo.lib.Event.getTarget(e);
52820 var cindex = this.view.findCellIndex(t);
52821 if(cindex !== false){
52822 return this.view.getHeaderCell(cindex);
52827 nextVisible : function(h){
52828 var v = this.view, cm = this.grid.colModel;
52831 if(!cm.isHidden(v.getCellIndex(h))){
52839 prevVisible : function(h){
52840 var v = this.view, cm = this.grid.colModel;
52843 if(!cm.isHidden(v.getCellIndex(h))){
52851 positionIndicator : function(h, n, e){
52852 var x = Roo.lib.Event.getPageX(e);
52853 var r = Roo.lib.Dom.getRegion(n.firstChild);
52854 var px, pt, py = r.top + this.proxyOffsets[1];
52855 if((r.right - x) <= (r.right-r.left)/2){
52856 px = r.right+this.view.borderWidth;
52862 var oldIndex = this.view.getCellIndex(h);
52863 var newIndex = this.view.getCellIndex(n);
52865 if(this.grid.colModel.isFixed(newIndex)){
52869 var locked = this.grid.colModel.isLocked(newIndex);
52874 if(oldIndex < newIndex){
52877 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
52880 px += this.proxyOffsets[0];
52881 this.proxyTop.setLeftTop(px, py);
52882 this.proxyTop.show();
52883 if(!this.bottomOffset){
52884 this.bottomOffset = this.view.mainHd.getHeight();
52886 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
52887 this.proxyBottom.show();
52891 onNodeEnter : function(n, dd, e, data){
52892 if(data.header != n){
52893 this.positionIndicator(data.header, n, e);
52897 onNodeOver : function(n, dd, e, data){
52898 var result = false;
52899 if(data.header != n){
52900 result = this.positionIndicator(data.header, n, e);
52903 this.proxyTop.hide();
52904 this.proxyBottom.hide();
52906 return result ? this.dropAllowed : this.dropNotAllowed;
52909 onNodeOut : function(n, dd, e, data){
52910 this.proxyTop.hide();
52911 this.proxyBottom.hide();
52914 onNodeDrop : function(n, dd, e, data){
52915 var h = data.header;
52917 var cm = this.grid.colModel;
52918 var x = Roo.lib.Event.getPageX(e);
52919 var r = Roo.lib.Dom.getRegion(n.firstChild);
52920 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
52921 var oldIndex = this.view.getCellIndex(h);
52922 var newIndex = this.view.getCellIndex(n);
52923 var locked = cm.isLocked(newIndex);
52927 if(oldIndex < newIndex){
52930 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
52933 cm.setLocked(oldIndex, locked, true);
52934 cm.moveColumn(oldIndex, newIndex);
52935 this.grid.fireEvent("columnmove", oldIndex, newIndex);
52943 * Ext JS Library 1.1.1
52944 * Copyright(c) 2006-2007, Ext JS, LLC.
52946 * Originally Released Under LGPL - original licence link has changed is not relivant.
52949 * <script type="text/javascript">
52953 * @class Roo.grid.GridView
52954 * @extends Roo.util.Observable
52957 * @param {Object} config
52959 Roo.grid.GridView = function(config){
52960 Roo.grid.GridView.superclass.constructor.call(this);
52963 Roo.apply(this, config);
52966 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
52968 unselectable : 'unselectable="on"',
52969 unselectableCls : 'x-unselectable',
52972 rowClass : "x-grid-row",
52974 cellClass : "x-grid-col",
52976 tdClass : "x-grid-td",
52978 hdClass : "x-grid-hd",
52980 splitClass : "x-grid-split",
52982 sortClasses : ["sort-asc", "sort-desc"],
52984 enableMoveAnim : false,
52988 dh : Roo.DomHelper,
52990 fly : Roo.Element.fly,
52992 css : Roo.util.CSS,
52998 scrollIncrement : 22,
53000 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
53002 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
53004 bind : function(ds, cm){
53006 this.ds.un("load", this.onLoad, this);
53007 this.ds.un("datachanged", this.onDataChange, this);
53008 this.ds.un("add", this.onAdd, this);
53009 this.ds.un("remove", this.onRemove, this);
53010 this.ds.un("update", this.onUpdate, this);
53011 this.ds.un("clear", this.onClear, this);
53014 ds.on("load", this.onLoad, this);
53015 ds.on("datachanged", this.onDataChange, this);
53016 ds.on("add", this.onAdd, this);
53017 ds.on("remove", this.onRemove, this);
53018 ds.on("update", this.onUpdate, this);
53019 ds.on("clear", this.onClear, this);
53024 this.cm.un("widthchange", this.onColWidthChange, this);
53025 this.cm.un("headerchange", this.onHeaderChange, this);
53026 this.cm.un("hiddenchange", this.onHiddenChange, this);
53027 this.cm.un("columnmoved", this.onColumnMove, this);
53028 this.cm.un("columnlockchange", this.onColumnLock, this);
53031 this.generateRules(cm);
53032 cm.on("widthchange", this.onColWidthChange, this);
53033 cm.on("headerchange", this.onHeaderChange, this);
53034 cm.on("hiddenchange", this.onHiddenChange, this);
53035 cm.on("columnmoved", this.onColumnMove, this);
53036 cm.on("columnlockchange", this.onColumnLock, this);
53041 init: function(grid){
53042 Roo.grid.GridView.superclass.init.call(this, grid);
53044 this.bind(grid.dataSource, grid.colModel);
53046 grid.on("headerclick", this.handleHeaderClick, this);
53048 if(grid.trackMouseOver){
53049 grid.on("mouseover", this.onRowOver, this);
53050 grid.on("mouseout", this.onRowOut, this);
53052 grid.cancelTextSelection = function(){};
53053 this.gridId = grid.id;
53055 var tpls = this.templates || {};
53058 tpls.master = new Roo.Template(
53059 '<div class="x-grid" hidefocus="true">',
53060 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
53061 '<div class="x-grid-topbar"></div>',
53062 '<div class="x-grid-scroller"><div></div></div>',
53063 '<div class="x-grid-locked">',
53064 '<div class="x-grid-header">{lockedHeader}</div>',
53065 '<div class="x-grid-body">{lockedBody}</div>',
53067 '<div class="x-grid-viewport">',
53068 '<div class="x-grid-header">{header}</div>',
53069 '<div class="x-grid-body">{body}</div>',
53071 '<div class="x-grid-bottombar"></div>',
53073 '<div class="x-grid-resize-proxy"> </div>',
53076 tpls.master.disableformats = true;
53080 tpls.header = new Roo.Template(
53081 '<table border="0" cellspacing="0" cellpadding="0">',
53082 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
53085 tpls.header.disableformats = true;
53087 tpls.header.compile();
53090 tpls.hcell = new Roo.Template(
53091 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
53092 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
53095 tpls.hcell.disableFormats = true;
53097 tpls.hcell.compile();
53100 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
53101 this.unselectableCls + '" ' + this.unselectable +'> </div>');
53102 tpls.hsplit.disableFormats = true;
53104 tpls.hsplit.compile();
53107 tpls.body = new Roo.Template(
53108 '<table border="0" cellspacing="0" cellpadding="0">',
53109 "<tbody>{rows}</tbody>",
53112 tpls.body.disableFormats = true;
53114 tpls.body.compile();
53117 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
53118 tpls.row.disableFormats = true;
53120 tpls.row.compile();
53123 tpls.cell = new Roo.Template(
53124 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
53125 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
53126 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
53129 tpls.cell.disableFormats = true;
53131 tpls.cell.compile();
53133 this.templates = tpls;
53136 // remap these for backwards compat
53137 onColWidthChange : function(){
53138 this.updateColumns.apply(this, arguments);
53140 onHeaderChange : function(){
53141 this.updateHeaders.apply(this, arguments);
53143 onHiddenChange : function(){
53144 this.handleHiddenChange.apply(this, arguments);
53146 onColumnMove : function(){
53147 this.handleColumnMove.apply(this, arguments);
53149 onColumnLock : function(){
53150 this.handleLockChange.apply(this, arguments);
53153 onDataChange : function(){
53155 this.updateHeaderSortState();
53158 onClear : function(){
53162 onUpdate : function(ds, record){
53163 this.refreshRow(record);
53166 refreshRow : function(record){
53167 var ds = this.ds, index;
53168 if(typeof record == 'number'){
53170 record = ds.getAt(index);
53172 index = ds.indexOf(record);
53174 this.insertRows(ds, index, index, true);
53175 this.onRemove(ds, record, index+1, true);
53176 this.syncRowHeights(index, index);
53178 this.fireEvent("rowupdated", this, index, record);
53181 onAdd : function(ds, records, index){
53182 this.insertRows(ds, index, index + (records.length-1));
53185 onRemove : function(ds, record, index, isUpdate){
53186 if(isUpdate !== true){
53187 this.fireEvent("beforerowremoved", this, index, record);
53189 var bt = this.getBodyTable(), lt = this.getLockedTable();
53190 if(bt.rows[index]){
53191 bt.firstChild.removeChild(bt.rows[index]);
53193 if(lt.rows[index]){
53194 lt.firstChild.removeChild(lt.rows[index]);
53196 if(isUpdate !== true){
53197 this.stripeRows(index);
53198 this.syncRowHeights(index, index);
53200 this.fireEvent("rowremoved", this, index, record);
53204 onLoad : function(){
53205 this.scrollToTop();
53209 * Scrolls the grid to the top
53211 scrollToTop : function(){
53213 this.scroller.dom.scrollTop = 0;
53219 * Gets a panel in the header of the grid that can be used for toolbars etc.
53220 * After modifying the contents of this panel a call to grid.autoSize() may be
53221 * required to register any changes in size.
53222 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53223 * @return Roo.Element
53225 getHeaderPanel : function(doShow){
53227 this.headerPanel.show();
53229 return this.headerPanel;
53233 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53234 * After modifying the contents of this panel a call to grid.autoSize() may be
53235 * required to register any changes in size.
53236 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53237 * @return Roo.Element
53239 getFooterPanel : function(doShow){
53241 this.footerPanel.show();
53243 return this.footerPanel;
53246 initElements : function(){
53247 var E = Roo.Element;
53248 var el = this.grid.getGridEl().dom.firstChild;
53249 var cs = el.childNodes;
53251 this.el = new E(el);
53253 this.focusEl = new E(el.firstChild);
53254 this.focusEl.swallowEvent("click", true);
53256 this.headerPanel = new E(cs[1]);
53257 this.headerPanel.enableDisplayMode("block");
53259 this.scroller = new E(cs[2]);
53260 this.scrollSizer = new E(this.scroller.dom.firstChild);
53262 this.lockedWrap = new E(cs[3]);
53263 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53264 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53266 this.mainWrap = new E(cs[4]);
53267 this.mainHd = new E(this.mainWrap.dom.firstChild);
53268 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53270 this.footerPanel = new E(cs[5]);
53271 this.footerPanel.enableDisplayMode("block");
53273 this.resizeProxy = new E(cs[6]);
53275 this.headerSelector = String.format(
53276 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53277 this.lockedHd.id, this.mainHd.id
53280 this.splitterSelector = String.format(
53281 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53282 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53285 idToCssName : function(s)
53287 return s.replace(/[^a-z0-9]+/ig, '-');
53290 getHeaderCell : function(index){
53291 return Roo.DomQuery.select(this.headerSelector)[index];
53294 getHeaderCellMeasure : function(index){
53295 return this.getHeaderCell(index).firstChild;
53298 getHeaderCellText : function(index){
53299 return this.getHeaderCell(index).firstChild.firstChild;
53302 getLockedTable : function(){
53303 return this.lockedBody.dom.firstChild;
53306 getBodyTable : function(){
53307 return this.mainBody.dom.firstChild;
53310 getLockedRow : function(index){
53311 return this.getLockedTable().rows[index];
53314 getRow : function(index){
53315 return this.getBodyTable().rows[index];
53318 getRowComposite : function(index){
53320 this.rowEl = new Roo.CompositeElementLite();
53322 var els = [], lrow, mrow;
53323 if(lrow = this.getLockedRow(index)){
53326 if(mrow = this.getRow(index)){
53329 this.rowEl.elements = els;
53333 * Gets the 'td' of the cell
53335 * @param {Integer} rowIndex row to select
53336 * @param {Integer} colIndex column to select
53340 getCell : function(rowIndex, colIndex){
53341 var locked = this.cm.getLockedCount();
53343 if(colIndex < locked){
53344 source = this.lockedBody.dom.firstChild;
53346 source = this.mainBody.dom.firstChild;
53347 colIndex -= locked;
53349 return source.rows[rowIndex].childNodes[colIndex];
53352 getCellText : function(rowIndex, colIndex){
53353 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53356 getCellBox : function(cell){
53357 var b = this.fly(cell).getBox();
53358 if(Roo.isOpera){ // opera fails to report the Y
53359 b.y = cell.offsetTop + this.mainBody.getY();
53364 getCellIndex : function(cell){
53365 var id = String(cell.className).match(this.cellRE);
53367 return parseInt(id[1], 10);
53372 findHeaderIndex : function(n){
53373 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53374 return r ? this.getCellIndex(r) : false;
53377 findHeaderCell : function(n){
53378 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53379 return r ? r : false;
53382 findRowIndex : function(n){
53386 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53387 return r ? r.rowIndex : false;
53390 findCellIndex : function(node){
53391 var stop = this.el.dom;
53392 while(node && node != stop){
53393 if(this.findRE.test(node.className)){
53394 return this.getCellIndex(node);
53396 node = node.parentNode;
53401 getColumnId : function(index){
53402 return this.cm.getColumnId(index);
53405 getSplitters : function()
53407 if(this.splitterSelector){
53408 return Roo.DomQuery.select(this.splitterSelector);
53414 getSplitter : function(index){
53415 return this.getSplitters()[index];
53418 onRowOver : function(e, t){
53420 if((row = this.findRowIndex(t)) !== false){
53421 this.getRowComposite(row).addClass("x-grid-row-over");
53425 onRowOut : function(e, t){
53427 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53428 this.getRowComposite(row).removeClass("x-grid-row-over");
53432 renderHeaders : function(){
53434 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53435 var cb = [], lb = [], sb = [], lsb = [], p = {};
53436 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53437 p.cellId = "x-grid-hd-0-" + i;
53438 p.splitId = "x-grid-csplit-0-" + i;
53439 p.id = cm.getColumnId(i);
53440 p.title = cm.getColumnTooltip(i) || "";
53441 p.value = cm.getColumnHeader(i) || "";
53442 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53443 if(!cm.isLocked(i)){
53444 cb[cb.length] = ct.apply(p);
53445 sb[sb.length] = st.apply(p);
53447 lb[lb.length] = ct.apply(p);
53448 lsb[lsb.length] = st.apply(p);
53451 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53452 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53455 updateHeaders : function(){
53456 var html = this.renderHeaders();
53457 this.lockedHd.update(html[0]);
53458 this.mainHd.update(html[1]);
53462 * Focuses the specified row.
53463 * @param {Number} row The row index
53465 focusRow : function(row)
53467 //Roo.log('GridView.focusRow');
53468 var x = this.scroller.dom.scrollLeft;
53469 this.focusCell(row, 0, false);
53470 this.scroller.dom.scrollLeft = x;
53474 * Focuses the specified cell.
53475 * @param {Number} row The row index
53476 * @param {Number} col The column index
53477 * @param {Boolean} hscroll false to disable horizontal scrolling
53479 focusCell : function(row, col, hscroll)
53481 //Roo.log('GridView.focusCell');
53482 var el = this.ensureVisible(row, col, hscroll);
53483 this.focusEl.alignTo(el, "tl-tl");
53485 this.focusEl.focus();
53487 this.focusEl.focus.defer(1, this.focusEl);
53492 * Scrolls the specified cell into view
53493 * @param {Number} row The row index
53494 * @param {Number} col The column index
53495 * @param {Boolean} hscroll false to disable horizontal scrolling
53497 ensureVisible : function(row, col, hscroll)
53499 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53500 //return null; //disable for testing.
53501 if(typeof row != "number"){
53502 row = row.rowIndex;
53504 if(row < 0 && row >= this.ds.getCount()){
53507 col = (col !== undefined ? col : 0);
53508 var cm = this.grid.colModel;
53509 while(cm.isHidden(col)){
53513 var el = this.getCell(row, col);
53517 var c = this.scroller.dom;
53519 var ctop = parseInt(el.offsetTop, 10);
53520 var cleft = parseInt(el.offsetLeft, 10);
53521 var cbot = ctop + el.offsetHeight;
53522 var cright = cleft + el.offsetWidth;
53524 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53525 var stop = parseInt(c.scrollTop, 10);
53526 var sleft = parseInt(c.scrollLeft, 10);
53527 var sbot = stop + ch;
53528 var sright = sleft + c.clientWidth;
53530 Roo.log('GridView.ensureVisible:' +
53532 ' c.clientHeight:' + c.clientHeight +
53533 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53541 c.scrollTop = ctop;
53542 //Roo.log("set scrolltop to ctop DISABLE?");
53543 }else if(cbot > sbot){
53544 //Roo.log("set scrolltop to cbot-ch");
53545 c.scrollTop = cbot-ch;
53548 if(hscroll !== false){
53550 c.scrollLeft = cleft;
53551 }else if(cright > sright){
53552 c.scrollLeft = cright-c.clientWidth;
53559 updateColumns : function(){
53560 this.grid.stopEditing();
53561 var cm = this.grid.colModel, colIds = this.getColumnIds();
53562 //var totalWidth = cm.getTotalWidth();
53564 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53565 //if(cm.isHidden(i)) continue;
53566 var w = cm.getColumnWidth(i);
53567 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53568 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53570 this.updateSplitters();
53573 generateRules : function(cm){
53574 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53575 Roo.util.CSS.removeStyleSheet(rulesId);
53576 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53577 var cid = cm.getColumnId(i);
53579 if(cm.config[i].align){
53580 align = 'text-align:'+cm.config[i].align+';';
53583 if(cm.isHidden(i)){
53584 hidden = 'display:none;';
53586 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53588 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53589 this.hdSelector, cid, " {\n", align, width, "}\n",
53590 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53591 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53593 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53596 updateSplitters : function(){
53597 var cm = this.cm, s = this.getSplitters();
53598 if(s){ // splitters not created yet
53599 var pos = 0, locked = true;
53600 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53601 if(cm.isHidden(i)) continue;
53602 var w = cm.getColumnWidth(i); // make sure it's a number
53603 if(!cm.isLocked(i) && locked){
53608 s[i].style.left = (pos-this.splitOffset) + "px";
53613 handleHiddenChange : function(colModel, colIndex, hidden){
53615 this.hideColumn(colIndex);
53617 this.unhideColumn(colIndex);
53621 hideColumn : function(colIndex){
53622 var cid = this.getColumnId(colIndex);
53623 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
53624 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
53626 this.updateHeaders();
53628 this.updateSplitters();
53632 unhideColumn : function(colIndex){
53633 var cid = this.getColumnId(colIndex);
53634 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
53635 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
53638 this.updateHeaders();
53640 this.updateSplitters();
53644 insertRows : function(dm, firstRow, lastRow, isUpdate){
53645 if(firstRow == 0 && lastRow == dm.getCount()-1){
53649 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
53651 var s = this.getScrollState();
53652 var markup = this.renderRows(firstRow, lastRow);
53653 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
53654 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
53655 this.restoreScroll(s);
53657 this.fireEvent("rowsinserted", this, firstRow, lastRow);
53658 this.syncRowHeights(firstRow, lastRow);
53659 this.stripeRows(firstRow);
53665 bufferRows : function(markup, target, index){
53666 var before = null, trows = target.rows, tbody = target.tBodies[0];
53667 if(index < trows.length){
53668 before = trows[index];
53670 var b = document.createElement("div");
53671 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
53672 var rows = b.firstChild.rows;
53673 for(var i = 0, len = rows.length; i < len; i++){
53675 tbody.insertBefore(rows[0], before);
53677 tbody.appendChild(rows[0]);
53684 deleteRows : function(dm, firstRow, lastRow){
53685 if(dm.getRowCount()<1){
53686 this.fireEvent("beforerefresh", this);
53687 this.mainBody.update("");
53688 this.lockedBody.update("");
53689 this.fireEvent("refresh", this);
53691 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
53692 var bt = this.getBodyTable();
53693 var tbody = bt.firstChild;
53694 var rows = bt.rows;
53695 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
53696 tbody.removeChild(rows[firstRow]);
53698 this.stripeRows(firstRow);
53699 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
53703 updateRows : function(dataSource, firstRow, lastRow){
53704 var s = this.getScrollState();
53706 this.restoreScroll(s);
53709 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
53713 this.updateHeaderSortState();
53716 getScrollState : function(){
53718 var sb = this.scroller.dom;
53719 return {left: sb.scrollLeft, top: sb.scrollTop};
53722 stripeRows : function(startRow){
53723 if(!this.grid.stripeRows || this.ds.getCount() < 1){
53726 startRow = startRow || 0;
53727 var rows = this.getBodyTable().rows;
53728 var lrows = this.getLockedTable().rows;
53729 var cls = ' x-grid-row-alt ';
53730 for(var i = startRow, len = rows.length; i < len; i++){
53731 var row = rows[i], lrow = lrows[i];
53732 var isAlt = ((i+1) % 2 == 0);
53733 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
53734 if(isAlt == hasAlt){
53738 row.className += " x-grid-row-alt";
53740 row.className = row.className.replace("x-grid-row-alt", "");
53743 lrow.className = row.className;
53748 restoreScroll : function(state){
53749 //Roo.log('GridView.restoreScroll');
53750 var sb = this.scroller.dom;
53751 sb.scrollLeft = state.left;
53752 sb.scrollTop = state.top;
53756 syncScroll : function(){
53757 //Roo.log('GridView.syncScroll');
53758 var sb = this.scroller.dom;
53759 var sh = this.mainHd.dom;
53760 var bs = this.mainBody.dom;
53761 var lv = this.lockedBody.dom;
53762 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
53763 lv.scrollTop = bs.scrollTop = sb.scrollTop;
53766 handleScroll : function(e){
53768 var sb = this.scroller.dom;
53769 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
53773 handleWheel : function(e){
53774 var d = e.getWheelDelta();
53775 this.scroller.dom.scrollTop -= d*22;
53776 // set this here to prevent jumpy scrolling on large tables
53777 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
53781 renderRows : function(startRow, endRow){
53782 // pull in all the crap needed to render rows
53783 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
53784 var colCount = cm.getColumnCount();
53786 if(ds.getCount() < 1){
53790 // build a map for all the columns
53792 for(var i = 0; i < colCount; i++){
53793 var name = cm.getDataIndex(i);
53795 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
53796 renderer : cm.getRenderer(i),
53797 id : cm.getColumnId(i),
53798 locked : cm.isLocked(i)
53802 startRow = startRow || 0;
53803 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
53805 // records to render
53806 var rs = ds.getRange(startRow, endRow);
53808 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
53811 // As much as I hate to duplicate code, this was branched because FireFox really hates
53812 // [].join("") on strings. The performance difference was substantial enough to
53813 // branch this function
53814 doRender : Roo.isGecko ?
53815 function(cs, rs, ds, startRow, colCount, stripe){
53816 var ts = this.templates, ct = ts.cell, rt = ts.row;
53818 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53820 var hasListener = this.grid.hasListener('rowclass');
53822 for(var j = 0, len = rs.length; j < len; j++){
53823 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
53824 for(var i = 0; i < colCount; i++){
53826 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53828 p.css = p.attr = "";
53829 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53830 if(p.value == undefined || p.value === "") p.value = " ";
53831 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53832 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53834 var markup = ct.apply(p);
53842 if(stripe && ((rowIndex+1) % 2 == 0)){
53843 alt.push("x-grid-row-alt")
53846 alt.push( " x-grid-dirty-row");
53849 if(this.getRowClass){
53850 alt.push(this.getRowClass(r, rowIndex));
53856 rowIndex : rowIndex,
53859 this.grid.fireEvent('rowclass', this, rowcfg);
53860 alt.push(rowcfg.rowClass);
53862 rp.alt = alt.join(" ");
53863 lbuf+= rt.apply(rp);
53865 buf+= rt.apply(rp);
53867 return [lbuf, buf];
53869 function(cs, rs, ds, startRow, colCount, stripe){
53870 var ts = this.templates, ct = ts.cell, rt = ts.row;
53872 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53873 var hasListener = this.grid.hasListener('rowclass');
53876 for(var j = 0, len = rs.length; j < len; j++){
53877 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
53878 for(var i = 0; i < colCount; i++){
53880 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53882 p.css = p.attr = "";
53883 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53884 if(p.value == undefined || p.value === "") p.value = " ";
53885 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53886 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53889 var markup = ct.apply(p);
53891 cb[cb.length] = markup;
53893 lcb[lcb.length] = markup;
53897 if(stripe && ((rowIndex+1) % 2 == 0)){
53898 alt.push( "x-grid-row-alt");
53901 alt.push(" x-grid-dirty-row");
53904 if(this.getRowClass){
53905 alt.push( this.getRowClass(r, rowIndex));
53911 rowIndex : rowIndex,
53914 this.grid.fireEvent('rowclass', this, rowcfg);
53915 alt.push(rowcfg.rowClass);
53917 rp.alt = alt.join(" ");
53918 rp.cells = lcb.join("");
53919 lbuf[lbuf.length] = rt.apply(rp);
53920 rp.cells = cb.join("");
53921 buf[buf.length] = rt.apply(rp);
53923 return [lbuf.join(""), buf.join("")];
53926 renderBody : function(){
53927 var markup = this.renderRows();
53928 var bt = this.templates.body;
53929 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
53933 * Refreshes the grid
53934 * @param {Boolean} headersToo
53936 refresh : function(headersToo){
53937 this.fireEvent("beforerefresh", this);
53938 this.grid.stopEditing();
53939 var result = this.renderBody();
53940 this.lockedBody.update(result[0]);
53941 this.mainBody.update(result[1]);
53942 if(headersToo === true){
53943 this.updateHeaders();
53944 this.updateColumns();
53945 this.updateSplitters();
53946 this.updateHeaderSortState();
53948 this.syncRowHeights();
53950 this.fireEvent("refresh", this);
53953 handleColumnMove : function(cm, oldIndex, newIndex){
53954 this.indexMap = null;
53955 var s = this.getScrollState();
53956 this.refresh(true);
53957 this.restoreScroll(s);
53958 this.afterMove(newIndex);
53961 afterMove : function(colIndex){
53962 if(this.enableMoveAnim && Roo.enableFx){
53963 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
53965 // if multisort - fix sortOrder, and reload..
53966 if (this.grid.dataSource.multiSort) {
53967 // the we can call sort again..
53968 var dm = this.grid.dataSource;
53969 var cm = this.grid.colModel;
53971 for(var i = 0; i < cm.config.length; i++ ) {
53973 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
53974 continue; // dont' bother, it's not in sort list or being set.
53977 so.push(cm.config[i].dataIndex);
53980 dm.load(dm.lastOptions);
53987 updateCell : function(dm, rowIndex, dataIndex){
53988 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
53989 if(typeof colIndex == "undefined"){ // not present in grid
53992 var cm = this.grid.colModel;
53993 var cell = this.getCell(rowIndex, colIndex);
53994 var cellText = this.getCellText(rowIndex, colIndex);
53997 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
53998 id : cm.getColumnId(colIndex),
53999 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
54001 var renderer = cm.getRenderer(colIndex);
54002 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
54003 if(typeof val == "undefined" || val === "") val = " ";
54004 cellText.innerHTML = val;
54005 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
54006 this.syncRowHeights(rowIndex, rowIndex);
54009 calcColumnWidth : function(colIndex, maxRowsToMeasure){
54011 if(this.grid.autoSizeHeaders){
54012 var h = this.getHeaderCellMeasure(colIndex);
54013 maxWidth = Math.max(maxWidth, h.scrollWidth);
54016 if(this.cm.isLocked(colIndex)){
54017 tb = this.getLockedTable();
54020 tb = this.getBodyTable();
54021 index = colIndex - this.cm.getLockedCount();
54024 var rows = tb.rows;
54025 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
54026 for(var i = 0; i < stopIndex; i++){
54027 var cell = rows[i].childNodes[index].firstChild;
54028 maxWidth = Math.max(maxWidth, cell.scrollWidth);
54031 return maxWidth + /*margin for error in IE*/ 5;
54034 * Autofit a column to its content.
54035 * @param {Number} colIndex
54036 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
54038 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
54039 if(this.cm.isHidden(colIndex)){
54040 return; // can't calc a hidden column
54043 var cid = this.cm.getColumnId(colIndex);
54044 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
54045 if(this.grid.autoSizeHeaders){
54046 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
54049 var newWidth = this.calcColumnWidth(colIndex);
54050 this.cm.setColumnWidth(colIndex,
54051 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
54052 if(!suppressEvent){
54053 this.grid.fireEvent("columnresize", colIndex, newWidth);
54058 * Autofits all columns to their content and then expands to fit any extra space in the grid
54060 autoSizeColumns : function(){
54061 var cm = this.grid.colModel;
54062 var colCount = cm.getColumnCount();
54063 for(var i = 0; i < colCount; i++){
54064 this.autoSizeColumn(i, true, true);
54066 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
54069 this.updateColumns();
54075 * Autofits all columns to the grid's width proportionate with their current size
54076 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
54078 fitColumns : function(reserveScrollSpace){
54079 var cm = this.grid.colModel;
54080 var colCount = cm.getColumnCount();
54084 for (i = 0; i < colCount; i++){
54085 if(!cm.isHidden(i) && !cm.isFixed(i)){
54086 w = cm.getColumnWidth(i);
54092 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
54093 if(reserveScrollSpace){
54096 var frac = (avail - cm.getTotalWidth())/width;
54097 while (cols.length){
54100 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
54102 this.updateColumns();
54106 onRowSelect : function(rowIndex){
54107 var row = this.getRowComposite(rowIndex);
54108 row.addClass("x-grid-row-selected");
54111 onRowDeselect : function(rowIndex){
54112 var row = this.getRowComposite(rowIndex);
54113 row.removeClass("x-grid-row-selected");
54116 onCellSelect : function(row, col){
54117 var cell = this.getCell(row, col);
54119 Roo.fly(cell).addClass("x-grid-cell-selected");
54123 onCellDeselect : function(row, col){
54124 var cell = this.getCell(row, col);
54126 Roo.fly(cell).removeClass("x-grid-cell-selected");
54130 updateHeaderSortState : function(){
54132 // sort state can be single { field: xxx, direction : yyy}
54133 // or { xxx=>ASC , yyy : DESC ..... }
54136 if (!this.ds.multiSort) {
54137 var state = this.ds.getSortState();
54141 mstate[state.field] = state.direction;
54142 // FIXME... - this is not used here.. but might be elsewhere..
54143 this.sortState = state;
54146 mstate = this.ds.sortToggle;
54148 //remove existing sort classes..
54150 var sc = this.sortClasses;
54151 var hds = this.el.select(this.headerSelector).removeClass(sc);
54153 for(var f in mstate) {
54155 var sortColumn = this.cm.findColumnIndex(f);
54157 if(sortColumn != -1){
54158 var sortDir = mstate[f];
54159 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54168 handleHeaderClick : function(g, index,e){
54170 Roo.log("header click");
54173 // touch events on header are handled by context
54174 this.handleHdCtx(g,index,e);
54179 if(this.headersDisabled){
54182 var dm = g.dataSource, cm = g.colModel;
54183 if(!cm.isSortable(index)){
54188 if (dm.multiSort) {
54189 // update the sortOrder
54191 for(var i = 0; i < cm.config.length; i++ ) {
54193 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54194 continue; // dont' bother, it's not in sort list or being set.
54197 so.push(cm.config[i].dataIndex);
54203 dm.sort(cm.getDataIndex(index));
54207 destroy : function(){
54209 this.colMenu.removeAll();
54210 Roo.menu.MenuMgr.unregister(this.colMenu);
54211 this.colMenu.getEl().remove();
54212 delete this.colMenu;
54215 this.hmenu.removeAll();
54216 Roo.menu.MenuMgr.unregister(this.hmenu);
54217 this.hmenu.getEl().remove();
54220 if(this.grid.enableColumnMove){
54221 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54223 for(var dd in dds){
54224 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54225 var elid = dds[dd].dragElId;
54227 Roo.get(elid).remove();
54228 } else if(dds[dd].config.isTarget){
54229 dds[dd].proxyTop.remove();
54230 dds[dd].proxyBottom.remove();
54233 if(Roo.dd.DDM.locationCache[dd]){
54234 delete Roo.dd.DDM.locationCache[dd];
54237 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54240 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54241 this.bind(null, null);
54242 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54245 handleLockChange : function(){
54246 this.refresh(true);
54249 onDenyColumnLock : function(){
54253 onDenyColumnHide : function(){
54257 handleHdMenuClick : function(item){
54258 var index = this.hdCtxIndex;
54259 var cm = this.cm, ds = this.ds;
54262 ds.sort(cm.getDataIndex(index), "ASC");
54265 ds.sort(cm.getDataIndex(index), "DESC");
54268 var lc = cm.getLockedCount();
54269 if(cm.getColumnCount(true) <= lc+1){
54270 this.onDenyColumnLock();
54274 cm.setLocked(index, true, true);
54275 cm.moveColumn(index, lc);
54276 this.grid.fireEvent("columnmove", index, lc);
54278 cm.setLocked(index, true);
54282 var lc = cm.getLockedCount();
54283 if((lc-1) != index){
54284 cm.setLocked(index, false, true);
54285 cm.moveColumn(index, lc-1);
54286 this.grid.fireEvent("columnmove", index, lc-1);
54288 cm.setLocked(index, false);
54291 case 'wider': // used to expand cols on touch..
54293 var cw = cm.getColumnWidth(index);
54294 cw += (item.id == 'wider' ? 1 : -1) * 50;
54295 cw = Math.max(0, cw);
54296 cw = Math.min(cw,4000);
54297 cm.setColumnWidth(index, cw);
54301 index = cm.getIndexById(item.id.substr(4));
54303 if(item.checked && cm.getColumnCount(true) <= 1){
54304 this.onDenyColumnHide();
54307 cm.setHidden(index, item.checked);
54313 beforeColMenuShow : function(){
54314 var cm = this.cm, colCount = cm.getColumnCount();
54315 this.colMenu.removeAll();
54316 for(var i = 0; i < colCount; i++){
54317 this.colMenu.add(new Roo.menu.CheckItem({
54318 id: "col-"+cm.getColumnId(i),
54319 text: cm.getColumnHeader(i),
54320 checked: !cm.isHidden(i),
54326 handleHdCtx : function(g, index, e){
54328 var hd = this.getHeaderCell(index);
54329 this.hdCtxIndex = index;
54330 var ms = this.hmenu.items, cm = this.cm;
54331 ms.get("asc").setDisabled(!cm.isSortable(index));
54332 ms.get("desc").setDisabled(!cm.isSortable(index));
54333 if(this.grid.enableColLock !== false){
54334 ms.get("lock").setDisabled(cm.isLocked(index));
54335 ms.get("unlock").setDisabled(!cm.isLocked(index));
54337 this.hmenu.show(hd, "tl-bl");
54340 handleHdOver : function(e){
54341 var hd = this.findHeaderCell(e.getTarget());
54342 if(hd && !this.headersDisabled){
54343 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54344 this.fly(hd).addClass("x-grid-hd-over");
54349 handleHdOut : function(e){
54350 var hd = this.findHeaderCell(e.getTarget());
54352 this.fly(hd).removeClass("x-grid-hd-over");
54356 handleSplitDblClick : function(e, t){
54357 var i = this.getCellIndex(t);
54358 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54359 this.autoSizeColumn(i, true);
54364 render : function(){
54367 var colCount = cm.getColumnCount();
54369 if(this.grid.monitorWindowResize === true){
54370 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54372 var header = this.renderHeaders();
54373 var body = this.templates.body.apply({rows:""});
54374 var html = this.templates.master.apply({
54377 lockedHeader: header[0],
54381 //this.updateColumns();
54383 this.grid.getGridEl().dom.innerHTML = html;
54385 this.initElements();
54387 // a kludge to fix the random scolling effect in webkit
54388 this.el.on("scroll", function() {
54389 this.el.dom.scrollTop=0; // hopefully not recursive..
54392 this.scroller.on("scroll", this.handleScroll, this);
54393 this.lockedBody.on("mousewheel", this.handleWheel, this);
54394 this.mainBody.on("mousewheel", this.handleWheel, this);
54396 this.mainHd.on("mouseover", this.handleHdOver, this);
54397 this.mainHd.on("mouseout", this.handleHdOut, this);
54398 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54399 {delegate: "."+this.splitClass});
54401 this.lockedHd.on("mouseover", this.handleHdOver, this);
54402 this.lockedHd.on("mouseout", this.handleHdOut, this);
54403 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54404 {delegate: "."+this.splitClass});
54406 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54407 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54410 this.updateSplitters();
54412 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54413 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54414 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54417 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54418 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54420 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54421 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54423 if(this.grid.enableColLock !== false){
54424 this.hmenu.add('-',
54425 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54426 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54430 this.hmenu.add('-',
54431 {id:"wider", text: this.columnsWiderText},
54432 {id:"narrow", text: this.columnsNarrowText }
54438 if(this.grid.enableColumnHide !== false){
54440 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54441 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54442 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54444 this.hmenu.add('-',
54445 {id:"columns", text: this.columnsText, menu: this.colMenu}
54448 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54450 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54453 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54454 this.dd = new Roo.grid.GridDragZone(this.grid, {
54455 ddGroup : this.grid.ddGroup || 'GridDD'
54461 for(var i = 0; i < colCount; i++){
54462 if(cm.isHidden(i)){
54463 this.hideColumn(i);
54465 if(cm.config[i].align){
54466 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54467 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54471 this.updateHeaderSortState();
54473 this.beforeInitialResize();
54476 // two part rendering gives faster view to the user
54477 this.renderPhase2.defer(1, this);
54480 renderPhase2 : function(){
54481 // render the rows now
54483 if(this.grid.autoSizeColumns){
54484 this.autoSizeColumns();
54488 beforeInitialResize : function(){
54492 onColumnSplitterMoved : function(i, w){
54493 this.userResized = true;
54494 var cm = this.grid.colModel;
54495 cm.setColumnWidth(i, w, true);
54496 var cid = cm.getColumnId(i);
54497 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54498 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54499 this.updateSplitters();
54501 this.grid.fireEvent("columnresize", i, w);
54504 syncRowHeights : function(startIndex, endIndex){
54505 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54506 startIndex = startIndex || 0;
54507 var mrows = this.getBodyTable().rows;
54508 var lrows = this.getLockedTable().rows;
54509 var len = mrows.length-1;
54510 endIndex = Math.min(endIndex || len, len);
54511 for(var i = startIndex; i <= endIndex; i++){
54512 var m = mrows[i], l = lrows[i];
54513 var h = Math.max(m.offsetHeight, l.offsetHeight);
54514 m.style.height = l.style.height = h + "px";
54519 layout : function(initialRender, is2ndPass){
54521 var auto = g.autoHeight;
54522 var scrollOffset = 16;
54523 var c = g.getGridEl(), cm = this.cm,
54524 expandCol = g.autoExpandColumn,
54526 //c.beginMeasure();
54528 if(!c.dom.offsetWidth){ // display:none?
54530 this.lockedWrap.show();
54531 this.mainWrap.show();
54536 var hasLock = this.cm.isLocked(0);
54538 var tbh = this.headerPanel.getHeight();
54539 var bbh = this.footerPanel.getHeight();
54542 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54543 var newHeight = ch + c.getBorderWidth("tb");
54545 newHeight = Math.min(g.maxHeight, newHeight);
54547 c.setHeight(newHeight);
54551 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54554 var s = this.scroller;
54556 var csize = c.getSize(true);
54558 this.el.setSize(csize.width, csize.height);
54560 this.headerPanel.setWidth(csize.width);
54561 this.footerPanel.setWidth(csize.width);
54563 var hdHeight = this.mainHd.getHeight();
54564 var vw = csize.width;
54565 var vh = csize.height - (tbh + bbh);
54569 var bt = this.getBodyTable();
54570 var ltWidth = hasLock ?
54571 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54573 var scrollHeight = bt.offsetHeight;
54574 var scrollWidth = ltWidth + bt.offsetWidth;
54575 var vscroll = false, hscroll = false;
54577 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54579 var lw = this.lockedWrap, mw = this.mainWrap;
54580 var lb = this.lockedBody, mb = this.mainBody;
54582 setTimeout(function(){
54583 var t = s.dom.offsetTop;
54584 var w = s.dom.clientWidth,
54585 h = s.dom.clientHeight;
54588 lw.setSize(ltWidth, h);
54590 mw.setLeftTop(ltWidth, t);
54591 mw.setSize(w-ltWidth, h);
54593 lb.setHeight(h-hdHeight);
54594 mb.setHeight(h-hdHeight);
54596 if(is2ndPass !== true && !gv.userResized && expandCol){
54597 // high speed resize without full column calculation
54599 var ci = cm.getIndexById(expandCol);
54601 ci = cm.findColumnIndex(expandCol);
54603 ci = Math.max(0, ci); // make sure it's got at least the first col.
54604 var expandId = cm.getColumnId(ci);
54605 var tw = cm.getTotalWidth(false);
54606 var currentWidth = cm.getColumnWidth(ci);
54607 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54608 if(currentWidth != cw){
54609 cm.setColumnWidth(ci, cw, true);
54610 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54611 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54612 gv.updateSplitters();
54613 gv.layout(false, true);
54625 onWindowResize : function(){
54626 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
54632 appendFooter : function(parentEl){
54636 sortAscText : "Sort Ascending",
54637 sortDescText : "Sort Descending",
54638 lockText : "Lock Column",
54639 unlockText : "Unlock Column",
54640 columnsText : "Columns",
54642 columnsWiderText : "Wider",
54643 columnsNarrowText : "Thinner"
54647 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
54648 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
54649 this.proxy.el.addClass('x-grid3-col-dd');
54652 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
54653 handleMouseDown : function(e){
54657 callHandleMouseDown : function(e){
54658 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
54663 * Ext JS Library 1.1.1
54664 * Copyright(c) 2006-2007, Ext JS, LLC.
54666 * Originally Released Under LGPL - original licence link has changed is not relivant.
54669 * <script type="text/javascript">
54673 // This is a support class used internally by the Grid components
54674 Roo.grid.SplitDragZone = function(grid, hd, hd2){
54676 this.view = grid.getView();
54677 this.proxy = this.view.resizeProxy;
54678 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
54679 "gridSplitters" + this.grid.getGridEl().id, {
54680 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
54682 this.setHandleElId(Roo.id(hd));
54683 this.setOuterHandleElId(Roo.id(hd2));
54684 this.scroll = false;
54686 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
54687 fly: Roo.Element.fly,
54689 b4StartDrag : function(x, y){
54690 this.view.headersDisabled = true;
54691 this.proxy.setHeight(this.view.mainWrap.getHeight());
54692 var w = this.cm.getColumnWidth(this.cellIndex);
54693 var minw = Math.max(w-this.grid.minColumnWidth, 0);
54694 this.resetConstraints();
54695 this.setXConstraint(minw, 1000);
54696 this.setYConstraint(0, 0);
54697 this.minX = x - minw;
54698 this.maxX = x + 1000;
54700 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
54704 handleMouseDown : function(e){
54705 ev = Roo.EventObject.setEvent(e);
54706 var t = this.fly(ev.getTarget());
54707 if(t.hasClass("x-grid-split")){
54708 this.cellIndex = this.view.getCellIndex(t.dom);
54709 this.split = t.dom;
54710 this.cm = this.grid.colModel;
54711 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
54712 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
54717 endDrag : function(e){
54718 this.view.headersDisabled = false;
54719 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
54720 var diff = endX - this.startPos;
54721 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
54724 autoOffset : function(){
54725 this.setDelta(0,0);
54729 * Ext JS Library 1.1.1
54730 * Copyright(c) 2006-2007, Ext JS, LLC.
54732 * Originally Released Under LGPL - original licence link has changed is not relivant.
54735 * <script type="text/javascript">
54739 // This is a support class used internally by the Grid components
54740 Roo.grid.GridDragZone = function(grid, config){
54741 this.view = grid.getView();
54742 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
54743 if(this.view.lockedBody){
54744 this.setHandleElId(Roo.id(this.view.mainBody.dom));
54745 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
54747 this.scroll = false;
54749 this.ddel = document.createElement('div');
54750 this.ddel.className = 'x-grid-dd-wrap';
54753 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
54754 ddGroup : "GridDD",
54756 getDragData : function(e){
54757 var t = Roo.lib.Event.getTarget(e);
54758 var rowIndex = this.view.findRowIndex(t);
54759 var sm = this.grid.selModel;
54761 //Roo.log(rowIndex);
54763 if (sm.getSelectedCell) {
54764 // cell selection..
54765 if (!sm.getSelectedCell()) {
54768 if (rowIndex != sm.getSelectedCell()[0]) {
54774 if(rowIndex !== false){
54779 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
54781 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
54784 if (e.hasModifier()){
54785 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
54788 Roo.log("getDragData");
54793 rowIndex: rowIndex,
54794 selections:sm.getSelections ? sm.getSelections() : (
54795 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
54802 onInitDrag : function(e){
54803 var data = this.dragData;
54804 this.ddel.innerHTML = this.grid.getDragDropText();
54805 this.proxy.update(this.ddel);
54806 // fire start drag?
54809 afterRepair : function(){
54810 this.dragging = false;
54813 getRepairXY : function(e, data){
54817 onEndDrag : function(data, e){
54821 onValidDrop : function(dd, e, id){
54826 beforeInvalidDrop : function(e, id){
54831 * Ext JS Library 1.1.1
54832 * Copyright(c) 2006-2007, Ext JS, LLC.
54834 * Originally Released Under LGPL - original licence link has changed is not relivant.
54837 * <script type="text/javascript">
54842 * @class Roo.grid.ColumnModel
54843 * @extends Roo.util.Observable
54844 * This is the default implementation of a ColumnModel used by the Grid. It defines
54845 * the columns in the grid.
54848 var colModel = new Roo.grid.ColumnModel([
54849 {header: "Ticker", width: 60, sortable: true, locked: true},
54850 {header: "Company Name", width: 150, sortable: true},
54851 {header: "Market Cap.", width: 100, sortable: true},
54852 {header: "$ Sales", width: 100, sortable: true, renderer: money},
54853 {header: "Employees", width: 100, sortable: true, resizable: false}
54858 * The config options listed for this class are options which may appear in each
54859 * individual column definition.
54860 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
54862 * @param {Object} config An Array of column config objects. See this class's
54863 * config objects for details.
54865 Roo.grid.ColumnModel = function(config){
54867 * The config passed into the constructor
54869 this.config = config;
54872 // if no id, create one
54873 // if the column does not have a dataIndex mapping,
54874 // map it to the order it is in the config
54875 for(var i = 0, len = config.length; i < len; i++){
54877 if(typeof c.dataIndex == "undefined"){
54880 if(typeof c.renderer == "string"){
54881 c.renderer = Roo.util.Format[c.renderer];
54883 if(typeof c.id == "undefined"){
54886 if(c.editor && c.editor.xtype){
54887 c.editor = Roo.factory(c.editor, Roo.grid);
54889 if(c.editor && c.editor.isFormField){
54890 c.editor = new Roo.grid.GridEditor(c.editor);
54892 this.lookup[c.id] = c;
54896 * The width of columns which have no width specified (defaults to 100)
54899 this.defaultWidth = 100;
54902 * Default sortable of columns which have no sortable specified (defaults to false)
54905 this.defaultSortable = false;
54909 * @event widthchange
54910 * Fires when the width of a column changes.
54911 * @param {ColumnModel} this
54912 * @param {Number} columnIndex The column index
54913 * @param {Number} newWidth The new width
54915 "widthchange": true,
54917 * @event headerchange
54918 * Fires when the text of a header changes.
54919 * @param {ColumnModel} this
54920 * @param {Number} columnIndex The column index
54921 * @param {Number} newText The new header text
54923 "headerchange": true,
54925 * @event hiddenchange
54926 * Fires when a column is hidden or "unhidden".
54927 * @param {ColumnModel} this
54928 * @param {Number} columnIndex The column index
54929 * @param {Boolean} hidden true if hidden, false otherwise
54931 "hiddenchange": true,
54933 * @event columnmoved
54934 * Fires when a column is moved.
54935 * @param {ColumnModel} this
54936 * @param {Number} oldIndex
54937 * @param {Number} newIndex
54939 "columnmoved" : true,
54941 * @event columlockchange
54942 * Fires when a column's locked state is changed
54943 * @param {ColumnModel} this
54944 * @param {Number} colIndex
54945 * @param {Boolean} locked true if locked
54947 "columnlockchange" : true
54949 Roo.grid.ColumnModel.superclass.constructor.call(this);
54951 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
54953 * @cfg {String} header The header text to display in the Grid view.
54956 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
54957 * {@link Roo.data.Record} definition from which to draw the column's value. If not
54958 * specified, the column's index is used as an index into the Record's data Array.
54961 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
54962 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
54965 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
54966 * Defaults to the value of the {@link #defaultSortable} property.
54967 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
54970 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
54973 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
54976 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
54979 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
54982 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
54983 * given the cell's data value. See {@link #setRenderer}. If not specified, the
54984 * default renderer uses the raw data value. If an object is returned (bootstrap only)
54985 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
54988 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
54991 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
54995 * Returns the id of the column at the specified index.
54996 * @param {Number} index The column index
54997 * @return {String} the id
54999 getColumnId : function(index){
55000 return this.config[index].id;
55004 * Returns the column for a specified id.
55005 * @param {String} id The column id
55006 * @return {Object} the column
55008 getColumnById : function(id){
55009 return this.lookup[id];
55014 * Returns the column for a specified dataIndex.
55015 * @param {String} dataIndex The column dataIndex
55016 * @return {Object|Boolean} the column or false if not found
55018 getColumnByDataIndex: function(dataIndex){
55019 var index = this.findColumnIndex(dataIndex);
55020 return index > -1 ? this.config[index] : false;
55024 * Returns the index for a specified column id.
55025 * @param {String} id The column id
55026 * @return {Number} the index, or -1 if not found
55028 getIndexById : function(id){
55029 for(var i = 0, len = this.config.length; i < len; i++){
55030 if(this.config[i].id == id){
55038 * Returns the index for a specified column dataIndex.
55039 * @param {String} dataIndex The column dataIndex
55040 * @return {Number} the index, or -1 if not found
55043 findColumnIndex : function(dataIndex){
55044 for(var i = 0, len = this.config.length; i < len; i++){
55045 if(this.config[i].dataIndex == dataIndex){
55053 moveColumn : function(oldIndex, newIndex){
55054 var c = this.config[oldIndex];
55055 this.config.splice(oldIndex, 1);
55056 this.config.splice(newIndex, 0, c);
55057 this.dataMap = null;
55058 this.fireEvent("columnmoved", this, oldIndex, newIndex);
55061 isLocked : function(colIndex){
55062 return this.config[colIndex].locked === true;
55065 setLocked : function(colIndex, value, suppressEvent){
55066 if(this.isLocked(colIndex) == value){
55069 this.config[colIndex].locked = value;
55070 if(!suppressEvent){
55071 this.fireEvent("columnlockchange", this, colIndex, value);
55075 getTotalLockedWidth : function(){
55076 var totalWidth = 0;
55077 for(var i = 0; i < this.config.length; i++){
55078 if(this.isLocked(i) && !this.isHidden(i)){
55079 this.totalWidth += this.getColumnWidth(i);
55085 getLockedCount : function(){
55086 for(var i = 0, len = this.config.length; i < len; i++){
55087 if(!this.isLocked(i)){
55094 * Returns the number of columns.
55097 getColumnCount : function(visibleOnly){
55098 if(visibleOnly === true){
55100 for(var i = 0, len = this.config.length; i < len; i++){
55101 if(!this.isHidden(i)){
55107 return this.config.length;
55111 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
55112 * @param {Function} fn
55113 * @param {Object} scope (optional)
55114 * @return {Array} result
55116 getColumnsBy : function(fn, scope){
55118 for(var i = 0, len = this.config.length; i < len; i++){
55119 var c = this.config[i];
55120 if(fn.call(scope||this, c, i) === true){
55128 * Returns true if the specified column is sortable.
55129 * @param {Number} col The column index
55130 * @return {Boolean}
55132 isSortable : function(col){
55133 if(typeof this.config[col].sortable == "undefined"){
55134 return this.defaultSortable;
55136 return this.config[col].sortable;
55140 * Returns the rendering (formatting) function defined for the column.
55141 * @param {Number} col The column index.
55142 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
55144 getRenderer : function(col){
55145 if(!this.config[col].renderer){
55146 return Roo.grid.ColumnModel.defaultRenderer;
55148 return this.config[col].renderer;
55152 * Sets the rendering (formatting) function for a column.
55153 * @param {Number} col The column index
55154 * @param {Function} fn The function to use to process the cell's raw data
55155 * to return HTML markup for the grid view. The render function is called with
55156 * the following parameters:<ul>
55157 * <li>Data value.</li>
55158 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
55159 * <li>css A CSS style string to apply to the table cell.</li>
55160 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55161 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55162 * <li>Row index</li>
55163 * <li>Column index</li>
55164 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55166 setRenderer : function(col, fn){
55167 this.config[col].renderer = fn;
55171 * Returns the width for the specified column.
55172 * @param {Number} col The column index
55175 getColumnWidth : function(col){
55176 return this.config[col].width * 1 || this.defaultWidth;
55180 * Sets the width for a column.
55181 * @param {Number} col The column index
55182 * @param {Number} width The new width
55184 setColumnWidth : function(col, width, suppressEvent){
55185 this.config[col].width = width;
55186 this.totalWidth = null;
55187 if(!suppressEvent){
55188 this.fireEvent("widthchange", this, col, width);
55193 * Returns the total width of all columns.
55194 * @param {Boolean} includeHidden True to include hidden column widths
55197 getTotalWidth : function(includeHidden){
55198 if(!this.totalWidth){
55199 this.totalWidth = 0;
55200 for(var i = 0, len = this.config.length; i < len; i++){
55201 if(includeHidden || !this.isHidden(i)){
55202 this.totalWidth += this.getColumnWidth(i);
55206 return this.totalWidth;
55210 * Returns the header for the specified column.
55211 * @param {Number} col The column index
55214 getColumnHeader : function(col){
55215 return this.config[col].header;
55219 * Sets the header for a column.
55220 * @param {Number} col The column index
55221 * @param {String} header The new header
55223 setColumnHeader : function(col, header){
55224 this.config[col].header = header;
55225 this.fireEvent("headerchange", this, col, header);
55229 * Returns the tooltip for the specified column.
55230 * @param {Number} col The column index
55233 getColumnTooltip : function(col){
55234 return this.config[col].tooltip;
55237 * Sets the tooltip for a column.
55238 * @param {Number} col The column index
55239 * @param {String} tooltip The new tooltip
55241 setColumnTooltip : function(col, tooltip){
55242 this.config[col].tooltip = tooltip;
55246 * Returns the dataIndex for the specified column.
55247 * @param {Number} col The column index
55250 getDataIndex : function(col){
55251 return this.config[col].dataIndex;
55255 * Sets the dataIndex for a column.
55256 * @param {Number} col The column index
55257 * @param {Number} dataIndex The new dataIndex
55259 setDataIndex : function(col, dataIndex){
55260 this.config[col].dataIndex = dataIndex;
55266 * Returns true if the cell is editable.
55267 * @param {Number} colIndex The column index
55268 * @param {Number} rowIndex The row index
55269 * @return {Boolean}
55271 isCellEditable : function(colIndex, rowIndex){
55272 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55276 * Returns the editor defined for the cell/column.
55277 * return false or null to disable editing.
55278 * @param {Number} colIndex The column index
55279 * @param {Number} rowIndex The row index
55282 getCellEditor : function(colIndex, rowIndex){
55283 return this.config[colIndex].editor;
55287 * Sets if a column is editable.
55288 * @param {Number} col The column index
55289 * @param {Boolean} editable True if the column is editable
55291 setEditable : function(col, editable){
55292 this.config[col].editable = editable;
55297 * Returns true if the column is hidden.
55298 * @param {Number} colIndex The column index
55299 * @return {Boolean}
55301 isHidden : function(colIndex){
55302 return this.config[colIndex].hidden;
55307 * Returns true if the column width cannot be changed
55309 isFixed : function(colIndex){
55310 return this.config[colIndex].fixed;
55314 * Returns true if the column can be resized
55315 * @return {Boolean}
55317 isResizable : function(colIndex){
55318 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55321 * Sets if a column is hidden.
55322 * @param {Number} colIndex The column index
55323 * @param {Boolean} hidden True if the column is hidden
55325 setHidden : function(colIndex, hidden){
55326 this.config[colIndex].hidden = hidden;
55327 this.totalWidth = null;
55328 this.fireEvent("hiddenchange", this, colIndex, hidden);
55332 * Sets the editor for a column.
55333 * @param {Number} col The column index
55334 * @param {Object} editor The editor object
55336 setEditor : function(col, editor){
55337 this.config[col].editor = editor;
55341 Roo.grid.ColumnModel.defaultRenderer = function(value){
55342 if(typeof value == "string" && value.length < 1){
55348 // Alias for backwards compatibility
55349 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55352 * Ext JS Library 1.1.1
55353 * Copyright(c) 2006-2007, Ext JS, LLC.
55355 * Originally Released Under LGPL - original licence link has changed is not relivant.
55358 * <script type="text/javascript">
55362 * @class Roo.grid.AbstractSelectionModel
55363 * @extends Roo.util.Observable
55364 * Abstract base class for grid SelectionModels. It provides the interface that should be
55365 * implemented by descendant classes. This class should not be directly instantiated.
55368 Roo.grid.AbstractSelectionModel = function(){
55369 this.locked = false;
55370 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55373 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55374 /** @ignore Called by the grid automatically. Do not call directly. */
55375 init : function(grid){
55381 * Locks the selections.
55384 this.locked = true;
55388 * Unlocks the selections.
55390 unlock : function(){
55391 this.locked = false;
55395 * Returns true if the selections are locked.
55396 * @return {Boolean}
55398 isLocked : function(){
55399 return this.locked;
55403 * Ext JS Library 1.1.1
55404 * Copyright(c) 2006-2007, Ext JS, LLC.
55406 * Originally Released Under LGPL - original licence link has changed is not relivant.
55409 * <script type="text/javascript">
55412 * @extends Roo.grid.AbstractSelectionModel
55413 * @class Roo.grid.RowSelectionModel
55414 * The default SelectionModel used by {@link Roo.grid.Grid}.
55415 * It supports multiple selections and keyboard selection/navigation.
55417 * @param {Object} config
55419 Roo.grid.RowSelectionModel = function(config){
55420 Roo.apply(this, config);
55421 this.selections = new Roo.util.MixedCollection(false, function(o){
55426 this.lastActive = false;
55430 * @event selectionchange
55431 * Fires when the selection changes
55432 * @param {SelectionModel} this
55434 "selectionchange" : true,
55436 * @event afterselectionchange
55437 * Fires after the selection changes (eg. by key press or clicking)
55438 * @param {SelectionModel} this
55440 "afterselectionchange" : true,
55442 * @event beforerowselect
55443 * Fires when a row is selected being selected, return false to cancel.
55444 * @param {SelectionModel} this
55445 * @param {Number} rowIndex The selected index
55446 * @param {Boolean} keepExisting False if other selections will be cleared
55448 "beforerowselect" : true,
55451 * Fires when a row is selected.
55452 * @param {SelectionModel} this
55453 * @param {Number} rowIndex The selected index
55454 * @param {Roo.data.Record} r The record
55456 "rowselect" : true,
55458 * @event rowdeselect
55459 * Fires when a row is deselected.
55460 * @param {SelectionModel} this
55461 * @param {Number} rowIndex The selected index
55463 "rowdeselect" : true
55465 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55466 this.locked = false;
55469 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55471 * @cfg {Boolean} singleSelect
55472 * True to allow selection of only one row at a time (defaults to false)
55474 singleSelect : false,
55477 initEvents : function(){
55479 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55480 this.grid.on("mousedown", this.handleMouseDown, this);
55481 }else{ // allow click to work like normal
55482 this.grid.on("rowclick", this.handleDragableRowClick, this);
55485 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55486 "up" : function(e){
55488 this.selectPrevious(e.shiftKey);
55489 }else if(this.last !== false && this.lastActive !== false){
55490 var last = this.last;
55491 this.selectRange(this.last, this.lastActive-1);
55492 this.grid.getView().focusRow(this.lastActive);
55493 if(last !== false){
55497 this.selectFirstRow();
55499 this.fireEvent("afterselectionchange", this);
55501 "down" : function(e){
55503 this.selectNext(e.shiftKey);
55504 }else if(this.last !== false && this.lastActive !== false){
55505 var last = this.last;
55506 this.selectRange(this.last, this.lastActive+1);
55507 this.grid.getView().focusRow(this.lastActive);
55508 if(last !== false){
55512 this.selectFirstRow();
55514 this.fireEvent("afterselectionchange", this);
55519 var view = this.grid.view;
55520 view.on("refresh", this.onRefresh, this);
55521 view.on("rowupdated", this.onRowUpdated, this);
55522 view.on("rowremoved", this.onRemove, this);
55526 onRefresh : function(){
55527 var ds = this.grid.dataSource, i, v = this.grid.view;
55528 var s = this.selections;
55529 s.each(function(r){
55530 if((i = ds.indexOfId(r.id)) != -1){
55539 onRemove : function(v, index, r){
55540 this.selections.remove(r);
55544 onRowUpdated : function(v, index, r){
55545 if(this.isSelected(r)){
55546 v.onRowSelect(index);
55552 * @param {Array} records The records to select
55553 * @param {Boolean} keepExisting (optional) True to keep existing selections
55555 selectRecords : function(records, keepExisting){
55557 this.clearSelections();
55559 var ds = this.grid.dataSource;
55560 for(var i = 0, len = records.length; i < len; i++){
55561 this.selectRow(ds.indexOf(records[i]), true);
55566 * Gets the number of selected rows.
55569 getCount : function(){
55570 return this.selections.length;
55574 * Selects the first row in the grid.
55576 selectFirstRow : function(){
55581 * Select the last row.
55582 * @param {Boolean} keepExisting (optional) True to keep existing selections
55584 selectLastRow : function(keepExisting){
55585 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55589 * Selects the row immediately following the last selected row.
55590 * @param {Boolean} keepExisting (optional) True to keep existing selections
55592 selectNext : function(keepExisting){
55593 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55594 this.selectRow(this.last+1, keepExisting);
55595 this.grid.getView().focusRow(this.last);
55600 * Selects the row that precedes the last selected row.
55601 * @param {Boolean} keepExisting (optional) True to keep existing selections
55603 selectPrevious : function(keepExisting){
55605 this.selectRow(this.last-1, keepExisting);
55606 this.grid.getView().focusRow(this.last);
55611 * Returns the selected records
55612 * @return {Array} Array of selected records
55614 getSelections : function(){
55615 return [].concat(this.selections.items);
55619 * Returns the first selected record.
55622 getSelected : function(){
55623 return this.selections.itemAt(0);
55628 * Clears all selections.
55630 clearSelections : function(fast){
55631 if(this.locked) return;
55633 var ds = this.grid.dataSource;
55634 var s = this.selections;
55635 s.each(function(r){
55636 this.deselectRow(ds.indexOfId(r.id));
55640 this.selections.clear();
55647 * Selects all rows.
55649 selectAll : function(){
55650 if(this.locked) return;
55651 this.selections.clear();
55652 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
55653 this.selectRow(i, true);
55658 * Returns True if there is a selection.
55659 * @return {Boolean}
55661 hasSelection : function(){
55662 return this.selections.length > 0;
55666 * Returns True if the specified row is selected.
55667 * @param {Number/Record} record The record or index of the record to check
55668 * @return {Boolean}
55670 isSelected : function(index){
55671 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
55672 return (r && this.selections.key(r.id) ? true : false);
55676 * Returns True if the specified record id is selected.
55677 * @param {String} id The id of record to check
55678 * @return {Boolean}
55680 isIdSelected : function(id){
55681 return (this.selections.key(id) ? true : false);
55685 handleMouseDown : function(e, t){
55686 var view = this.grid.getView(), rowIndex;
55687 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
55690 if(e.shiftKey && this.last !== false){
55691 var last = this.last;
55692 this.selectRange(last, rowIndex, e.ctrlKey);
55693 this.last = last; // reset the last
55694 view.focusRow(rowIndex);
55696 var isSelected = this.isSelected(rowIndex);
55697 if(e.button !== 0 && isSelected){
55698 view.focusRow(rowIndex);
55699 }else if(e.ctrlKey && isSelected){
55700 this.deselectRow(rowIndex);
55701 }else if(!isSelected){
55702 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
55703 view.focusRow(rowIndex);
55706 this.fireEvent("afterselectionchange", this);
55709 handleDragableRowClick : function(grid, rowIndex, e)
55711 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
55712 this.selectRow(rowIndex, false);
55713 grid.view.focusRow(rowIndex);
55714 this.fireEvent("afterselectionchange", this);
55719 * Selects multiple rows.
55720 * @param {Array} rows Array of the indexes of the row to select
55721 * @param {Boolean} keepExisting (optional) True to keep existing selections
55723 selectRows : function(rows, keepExisting){
55725 this.clearSelections();
55727 for(var i = 0, len = rows.length; i < len; i++){
55728 this.selectRow(rows[i], true);
55733 * Selects a range of rows. All rows in between startRow and endRow are also selected.
55734 * @param {Number} startRow The index of the first row in the range
55735 * @param {Number} endRow The index of the last row in the range
55736 * @param {Boolean} keepExisting (optional) True to retain existing selections
55738 selectRange : function(startRow, endRow, keepExisting){
55739 if(this.locked) return;
55741 this.clearSelections();
55743 if(startRow <= endRow){
55744 for(var i = startRow; i <= endRow; i++){
55745 this.selectRow(i, true);
55748 for(var i = startRow; i >= endRow; i--){
55749 this.selectRow(i, true);
55755 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
55756 * @param {Number} startRow The index of the first row in the range
55757 * @param {Number} endRow The index of the last row in the range
55759 deselectRange : function(startRow, endRow, preventViewNotify){
55760 if(this.locked) return;
55761 for(var i = startRow; i <= endRow; i++){
55762 this.deselectRow(i, preventViewNotify);
55768 * @param {Number} row The index of the row to select
55769 * @param {Boolean} keepExisting (optional) True to keep existing selections
55771 selectRow : function(index, keepExisting, preventViewNotify){
55772 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
55773 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
55774 if(!keepExisting || this.singleSelect){
55775 this.clearSelections();
55777 var r = this.grid.dataSource.getAt(index);
55778 this.selections.add(r);
55779 this.last = this.lastActive = index;
55780 if(!preventViewNotify){
55781 this.grid.getView().onRowSelect(index);
55783 this.fireEvent("rowselect", this, index, r);
55784 this.fireEvent("selectionchange", this);
55790 * @param {Number} row The index of the row to deselect
55792 deselectRow : function(index, preventViewNotify){
55793 if(this.locked) return;
55794 if(this.last == index){
55797 if(this.lastActive == index){
55798 this.lastActive = false;
55800 var r = this.grid.dataSource.getAt(index);
55801 this.selections.remove(r);
55802 if(!preventViewNotify){
55803 this.grid.getView().onRowDeselect(index);
55805 this.fireEvent("rowdeselect", this, index);
55806 this.fireEvent("selectionchange", this);
55810 restoreLast : function(){
55812 this.last = this._last;
55817 acceptsNav : function(row, col, cm){
55818 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55822 onEditorKey : function(field, e){
55823 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
55828 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55830 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55832 }else if(k == e.ENTER && !e.ctrlKey){
55836 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
55838 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
55840 }else if(k == e.ESC){
55844 g.startEditing(newCell[0], newCell[1]);
55849 * Ext JS Library 1.1.1
55850 * Copyright(c) 2006-2007, Ext JS, LLC.
55852 * Originally Released Under LGPL - original licence link has changed is not relivant.
55855 * <script type="text/javascript">
55858 * @class Roo.grid.CellSelectionModel
55859 * @extends Roo.grid.AbstractSelectionModel
55860 * This class provides the basic implementation for cell selection in a grid.
55862 * @param {Object} config The object containing the configuration of this model.
55863 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
55865 Roo.grid.CellSelectionModel = function(config){
55866 Roo.apply(this, config);
55868 this.selection = null;
55872 * @event beforerowselect
55873 * Fires before a cell is selected.
55874 * @param {SelectionModel} this
55875 * @param {Number} rowIndex The selected row index
55876 * @param {Number} colIndex The selected cell index
55878 "beforecellselect" : true,
55880 * @event cellselect
55881 * Fires when a cell is selected.
55882 * @param {SelectionModel} this
55883 * @param {Number} rowIndex The selected row index
55884 * @param {Number} colIndex The selected cell index
55886 "cellselect" : true,
55888 * @event selectionchange
55889 * Fires when the active selection changes.
55890 * @param {SelectionModel} this
55891 * @param {Object} selection null for no selection or an object (o) with two properties
55893 <li>o.record: the record object for the row the selection is in</li>
55894 <li>o.cell: An array of [rowIndex, columnIndex]</li>
55897 "selectionchange" : true,
55900 * Fires when the tab (or enter) was pressed on the last editable cell
55901 * You can use this to trigger add new row.
55902 * @param {SelectionModel} this
55906 * @event beforeeditnext
55907 * Fires before the next editable sell is made active
55908 * You can use this to skip to another cell or fire the tabend
55909 * if you set cell to false
55910 * @param {Object} eventdata object : { cell : [ row, col ] }
55912 "beforeeditnext" : true
55914 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
55917 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
55919 enter_is_tab: false,
55922 initEvents : function(){
55923 this.grid.on("mousedown", this.handleMouseDown, this);
55924 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
55925 var view = this.grid.view;
55926 view.on("refresh", this.onViewChange, this);
55927 view.on("rowupdated", this.onRowUpdated, this);
55928 view.on("beforerowremoved", this.clearSelections, this);
55929 view.on("beforerowsinserted", this.clearSelections, this);
55930 if(this.grid.isEditor){
55931 this.grid.on("beforeedit", this.beforeEdit, this);
55936 beforeEdit : function(e){
55937 this.select(e.row, e.column, false, true, e.record);
55941 onRowUpdated : function(v, index, r){
55942 if(this.selection && this.selection.record == r){
55943 v.onCellSelect(index, this.selection.cell[1]);
55948 onViewChange : function(){
55949 this.clearSelections(true);
55953 * Returns the currently selected cell,.
55954 * @return {Array} The selected cell (row, column) or null if none selected.
55956 getSelectedCell : function(){
55957 return this.selection ? this.selection.cell : null;
55961 * Clears all selections.
55962 * @param {Boolean} true to prevent the gridview from being notified about the change.
55964 clearSelections : function(preventNotify){
55965 var s = this.selection;
55967 if(preventNotify !== true){
55968 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
55970 this.selection = null;
55971 this.fireEvent("selectionchange", this, null);
55976 * Returns true if there is a selection.
55977 * @return {Boolean}
55979 hasSelection : function(){
55980 return this.selection ? true : false;
55984 handleMouseDown : function(e, t){
55985 var v = this.grid.getView();
55986 if(this.isLocked()){
55989 var row = v.findRowIndex(t);
55990 var cell = v.findCellIndex(t);
55991 if(row !== false && cell !== false){
55992 this.select(row, cell);
55998 * @param {Number} rowIndex
55999 * @param {Number} collIndex
56001 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
56002 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
56003 this.clearSelections();
56004 r = r || this.grid.dataSource.getAt(rowIndex);
56007 cell : [rowIndex, colIndex]
56009 if(!preventViewNotify){
56010 var v = this.grid.getView();
56011 v.onCellSelect(rowIndex, colIndex);
56012 if(preventFocus !== true){
56013 v.focusCell(rowIndex, colIndex);
56016 this.fireEvent("cellselect", this, rowIndex, colIndex);
56017 this.fireEvent("selectionchange", this, this.selection);
56022 isSelectable : function(rowIndex, colIndex, cm){
56023 return !cm.isHidden(colIndex);
56027 handleKeyDown : function(e){
56028 //Roo.log('Cell Sel Model handleKeyDown');
56029 if(!e.isNavKeyPress()){
56032 var g = this.grid, s = this.selection;
56035 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
56037 this.select(cell[0], cell[1]);
56042 var walk = function(row, col, step){
56043 return g.walkCells(row, col, step, sm.isSelectable, sm);
56045 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
56052 // handled by onEditorKey
56053 if (g.isEditor && g.editing) {
56057 newCell = walk(r, c-1, -1);
56059 newCell = walk(r, c+1, 1);
56064 newCell = walk(r+1, c, 1);
56068 newCell = walk(r-1, c, -1);
56072 newCell = walk(r, c+1, 1);
56076 newCell = walk(r, c-1, -1);
56081 if(g.isEditor && !g.editing){
56082 g.startEditing(r, c);
56091 this.select(newCell[0], newCell[1]);
56097 acceptsNav : function(row, col, cm){
56098 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56102 * @param {Number} field (not used) - as it's normally used as a listener
56103 * @param {Number} e - event - fake it by using
56105 * var e = Roo.EventObjectImpl.prototype;
56106 * e.keyCode = e.TAB
56110 onEditorKey : function(field, e){
56112 var k = e.getKey(),
56115 ed = g.activeEditor,
56117 ///Roo.log('onEditorKey' + k);
56120 if (this.enter_is_tab && k == e.ENTER) {
56126 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56128 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56134 } else if(k == e.ENTER && !e.ctrlKey){
56137 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56139 } else if(k == e.ESC){
56144 var ecall = { cell : newCell, forward : forward };
56145 this.fireEvent('beforeeditnext', ecall );
56146 newCell = ecall.cell;
56147 forward = ecall.forward;
56151 //Roo.log('next cell after edit');
56152 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
56153 } else if (forward) {
56154 // tabbed past last
56155 this.fireEvent.defer(100, this, ['tabend',this]);
56160 * Ext JS Library 1.1.1
56161 * Copyright(c) 2006-2007, Ext JS, LLC.
56163 * Originally Released Under LGPL - original licence link has changed is not relivant.
56166 * <script type="text/javascript">
56170 * @class Roo.grid.EditorGrid
56171 * @extends Roo.grid.Grid
56172 * Class for creating and editable grid.
56173 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56174 * The container MUST have some type of size defined for the grid to fill. The container will be
56175 * automatically set to position relative if it isn't already.
56176 * @param {Object} dataSource The data model to bind to
56177 * @param {Object} colModel The column model with info about this grid's columns
56179 Roo.grid.EditorGrid = function(container, config){
56180 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56181 this.getGridEl().addClass("xedit-grid");
56183 if(!this.selModel){
56184 this.selModel = new Roo.grid.CellSelectionModel();
56187 this.activeEditor = null;
56191 * @event beforeedit
56192 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56193 * <ul style="padding:5px;padding-left:16px;">
56194 * <li>grid - This grid</li>
56195 * <li>record - The record being edited</li>
56196 * <li>field - The field name being edited</li>
56197 * <li>value - The value for the field being edited.</li>
56198 * <li>row - The grid row index</li>
56199 * <li>column - The grid column index</li>
56200 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56202 * @param {Object} e An edit event (see above for description)
56204 "beforeedit" : true,
56207 * Fires after a cell is edited. <br />
56208 * <ul style="padding:5px;padding-left:16px;">
56209 * <li>grid - This grid</li>
56210 * <li>record - The record being edited</li>
56211 * <li>field - The field name being edited</li>
56212 * <li>value - The value being set</li>
56213 * <li>originalValue - The original value for the field, before the edit.</li>
56214 * <li>row - The grid row index</li>
56215 * <li>column - The grid column index</li>
56217 * @param {Object} e An edit event (see above for description)
56219 "afteredit" : true,
56221 * @event validateedit
56222 * Fires after a cell is edited, but before the value is set in the record.
56223 * You can use this to modify the value being set in the field, Return false
56224 * to cancel the change. The edit event object has the following properties <br />
56225 * <ul style="padding:5px;padding-left:16px;">
56226 * <li>editor - This editor</li>
56227 * <li>grid - This grid</li>
56228 * <li>record - The record being edited</li>
56229 * <li>field - The field name being edited</li>
56230 * <li>value - The value being set</li>
56231 * <li>originalValue - The original value for the field, before the edit.</li>
56232 * <li>row - The grid row index</li>
56233 * <li>column - The grid column index</li>
56234 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56236 * @param {Object} e An edit event (see above for description)
56238 "validateedit" : true
56240 this.on("bodyscroll", this.stopEditing, this);
56241 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56244 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56246 * @cfg {Number} clicksToEdit
56247 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56254 trackMouseOver: false, // causes very odd FF errors
56256 onCellDblClick : function(g, row, col){
56257 this.startEditing(row, col);
56260 onEditComplete : function(ed, value, startValue){
56261 this.editing = false;
56262 this.activeEditor = null;
56263 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56265 var field = this.colModel.getDataIndex(ed.col);
56270 originalValue: startValue,
56277 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56280 if(String(value) !== String(startValue)){
56282 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56283 r.set(field, e.value);
56284 // if we are dealing with a combo box..
56285 // then we also set the 'name' colum to be the displayField
56286 if (ed.field.displayField && ed.field.name) {
56287 r.set(ed.field.name, ed.field.el.dom.value);
56290 delete e.cancel; //?? why!!!
56291 this.fireEvent("afteredit", e);
56294 this.fireEvent("afteredit", e); // always fire it!
56296 this.view.focusCell(ed.row, ed.col);
56300 * Starts editing the specified for the specified row/column
56301 * @param {Number} rowIndex
56302 * @param {Number} colIndex
56304 startEditing : function(row, col){
56305 this.stopEditing();
56306 if(this.colModel.isCellEditable(col, row)){
56307 this.view.ensureVisible(row, col, true);
56309 var r = this.dataSource.getAt(row);
56310 var field = this.colModel.getDataIndex(col);
56311 var cell = Roo.get(this.view.getCell(row,col));
56316 value: r.data[field],
56321 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56322 this.editing = true;
56323 var ed = this.colModel.getCellEditor(col, row);
56329 ed.render(ed.parentEl || document.body);
56335 (function(){ // complex but required for focus issues in safari, ie and opera
56339 ed.on("complete", this.onEditComplete, this, {single: true});
56340 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56341 this.activeEditor = ed;
56342 var v = r.data[field];
56343 ed.startEdit(this.view.getCell(row, col), v);
56344 // combo's with 'displayField and name set
56345 if (ed.field.displayField && ed.field.name) {
56346 ed.field.el.dom.value = r.data[ed.field.name];
56350 }).defer(50, this);
56356 * Stops any active editing
56358 stopEditing : function(){
56359 if(this.activeEditor){
56360 this.activeEditor.completeEdit();
56362 this.activeEditor = null;
56366 * Called to get grid's drag proxy text, by default returns this.ddText.
56369 getDragDropText : function(){
56370 var count = this.selModel.getSelectedCell() ? 1 : 0;
56371 return String.format(this.ddText, count, count == 1 ? '' : 's');
56376 * Ext JS Library 1.1.1
56377 * Copyright(c) 2006-2007, Ext JS, LLC.
56379 * Originally Released Under LGPL - original licence link has changed is not relivant.
56382 * <script type="text/javascript">
56385 // private - not really -- you end up using it !
56386 // This is a support class used internally by the Grid components
56389 * @class Roo.grid.GridEditor
56390 * @extends Roo.Editor
56391 * Class for creating and editable grid elements.
56392 * @param {Object} config any settings (must include field)
56394 Roo.grid.GridEditor = function(field, config){
56395 if (!config && field.field) {
56397 field = Roo.factory(config.field, Roo.form);
56399 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56400 field.monitorTab = false;
56403 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56406 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56409 alignment: "tl-tl",
56412 cls: "x-small-editor x-grid-editor",
56417 * Ext JS Library 1.1.1
56418 * Copyright(c) 2006-2007, Ext JS, LLC.
56420 * Originally Released Under LGPL - original licence link has changed is not relivant.
56423 * <script type="text/javascript">
56428 Roo.grid.PropertyRecord = Roo.data.Record.create([
56429 {name:'name',type:'string'}, 'value'
56433 Roo.grid.PropertyStore = function(grid, source){
56435 this.store = new Roo.data.Store({
56436 recordType : Roo.grid.PropertyRecord
56438 this.store.on('update', this.onUpdate, this);
56440 this.setSource(source);
56442 Roo.grid.PropertyStore.superclass.constructor.call(this);
56447 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56448 setSource : function(o){
56450 this.store.removeAll();
56453 if(this.isEditableValue(o[k])){
56454 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56457 this.store.loadRecords({records: data}, {}, true);
56460 onUpdate : function(ds, record, type){
56461 if(type == Roo.data.Record.EDIT){
56462 var v = record.data['value'];
56463 var oldValue = record.modified['value'];
56464 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56465 this.source[record.id] = v;
56467 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56474 getProperty : function(row){
56475 return this.store.getAt(row);
56478 isEditableValue: function(val){
56479 if(val && val instanceof Date){
56481 }else if(typeof val == 'object' || typeof val == 'function'){
56487 setValue : function(prop, value){
56488 this.source[prop] = value;
56489 this.store.getById(prop).set('value', value);
56492 getSource : function(){
56493 return this.source;
56497 Roo.grid.PropertyColumnModel = function(grid, store){
56500 g.PropertyColumnModel.superclass.constructor.call(this, [
56501 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56502 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56504 this.store = store;
56505 this.bselect = Roo.DomHelper.append(document.body, {
56506 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56507 {tag: 'option', value: 'true', html: 'true'},
56508 {tag: 'option', value: 'false', html: 'false'}
56511 Roo.id(this.bselect);
56514 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56515 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56516 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56517 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56518 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56520 this.renderCellDelegate = this.renderCell.createDelegate(this);
56521 this.renderPropDelegate = this.renderProp.createDelegate(this);
56524 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56528 valueText : 'Value',
56530 dateFormat : 'm/j/Y',
56533 renderDate : function(dateVal){
56534 return dateVal.dateFormat(this.dateFormat);
56537 renderBool : function(bVal){
56538 return bVal ? 'true' : 'false';
56541 isCellEditable : function(colIndex, rowIndex){
56542 return colIndex == 1;
56545 getRenderer : function(col){
56547 this.renderCellDelegate : this.renderPropDelegate;
56550 renderProp : function(v){
56551 return this.getPropertyName(v);
56554 renderCell : function(val){
56556 if(val instanceof Date){
56557 rv = this.renderDate(val);
56558 }else if(typeof val == 'boolean'){
56559 rv = this.renderBool(val);
56561 return Roo.util.Format.htmlEncode(rv);
56564 getPropertyName : function(name){
56565 var pn = this.grid.propertyNames;
56566 return pn && pn[name] ? pn[name] : name;
56569 getCellEditor : function(colIndex, rowIndex){
56570 var p = this.store.getProperty(rowIndex);
56571 var n = p.data['name'], val = p.data['value'];
56573 if(typeof(this.grid.customEditors[n]) == 'string'){
56574 return this.editors[this.grid.customEditors[n]];
56576 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56577 return this.grid.customEditors[n];
56579 if(val instanceof Date){
56580 return this.editors['date'];
56581 }else if(typeof val == 'number'){
56582 return this.editors['number'];
56583 }else if(typeof val == 'boolean'){
56584 return this.editors['boolean'];
56586 return this.editors['string'];
56592 * @class Roo.grid.PropertyGrid
56593 * @extends Roo.grid.EditorGrid
56594 * This class represents the interface of a component based property grid control.
56595 * <br><br>Usage:<pre><code>
56596 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56604 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56605 * The container MUST have some type of size defined for the grid to fill. The container will be
56606 * automatically set to position relative if it isn't already.
56607 * @param {Object} config A config object that sets properties on this grid.
56609 Roo.grid.PropertyGrid = function(container, config){
56610 config = config || {};
56611 var store = new Roo.grid.PropertyStore(this);
56612 this.store = store;
56613 var cm = new Roo.grid.PropertyColumnModel(this, store);
56614 store.store.sort('name', 'ASC');
56615 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
56618 enableColLock:false,
56619 enableColumnMove:false,
56621 trackMouseOver: false,
56624 this.getGridEl().addClass('x-props-grid');
56625 this.lastEditRow = null;
56626 this.on('columnresize', this.onColumnResize, this);
56629 * @event beforepropertychange
56630 * Fires before a property changes (return false to stop?)
56631 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56632 * @param {String} id Record Id
56633 * @param {String} newval New Value
56634 * @param {String} oldval Old Value
56636 "beforepropertychange": true,
56638 * @event propertychange
56639 * Fires after a property changes
56640 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56641 * @param {String} id Record Id
56642 * @param {String} newval New Value
56643 * @param {String} oldval Old Value
56645 "propertychange": true
56647 this.customEditors = this.customEditors || {};
56649 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
56652 * @cfg {Object} customEditors map of colnames=> custom editors.
56653 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
56654 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
56655 * false disables editing of the field.
56659 * @cfg {Object} propertyNames map of property Names to their displayed value
56662 render : function(){
56663 Roo.grid.PropertyGrid.superclass.render.call(this);
56664 this.autoSize.defer(100, this);
56667 autoSize : function(){
56668 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
56670 this.view.fitColumns();
56674 onColumnResize : function(){
56675 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
56679 * Sets the data for the Grid
56680 * accepts a Key => Value object of all the elements avaiable.
56681 * @param {Object} data to appear in grid.
56683 setSource : function(source){
56684 this.store.setSource(source);
56688 * Gets all the data from the grid.
56689 * @return {Object} data data stored in grid
56691 getSource : function(){
56692 return this.store.getSource();
56701 * @class Roo.grid.Calendar
56702 * @extends Roo.util.Grid
56703 * This class extends the Grid to provide a calendar widget
56704 * <br><br>Usage:<pre><code>
56705 var grid = new Roo.grid.Calendar("my-container-id", {
56708 selModel: mySelectionModel,
56709 autoSizeColumns: true,
56710 monitorWindowResize: false,
56711 trackMouseOver: true
56712 eventstore : real data store..
56718 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56719 * The container MUST have some type of size defined for the grid to fill. The container will be
56720 * automatically set to position relative if it isn't already.
56721 * @param {Object} config A config object that sets properties on this grid.
56723 Roo.grid.Calendar = function(container, config){
56724 // initialize the container
56725 this.container = Roo.get(container);
56726 this.container.update("");
56727 this.container.setStyle("overflow", "hidden");
56728 this.container.addClass('x-grid-container');
56730 this.id = this.container.id;
56732 Roo.apply(this, config);
56733 // check and correct shorthanded configs
56737 for (var r = 0;r < 6;r++) {
56740 for (var c =0;c < 7;c++) {
56744 if (this.eventStore) {
56745 this.eventStore= Roo.factory(this.eventStore, Roo.data);
56746 this.eventStore.on('load',this.onLoad, this);
56747 this.eventStore.on('beforeload',this.clearEvents, this);
56751 this.dataSource = new Roo.data.Store({
56752 proxy: new Roo.data.MemoryProxy(rows),
56753 reader: new Roo.data.ArrayReader({}, [
56754 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
56757 this.dataSource.load();
56758 this.ds = this.dataSource;
56759 this.ds.xmodule = this.xmodule || false;
56762 var cellRender = function(v,x,r)
56764 return String.format(
56765 '<div class="fc-day fc-widget-content"><div>' +
56766 '<div class="fc-event-container"></div>' +
56767 '<div class="fc-day-number">{0}</div>'+
56769 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
56770 '</div></div>', v);
56775 this.colModel = new Roo.grid.ColumnModel( [
56777 xtype: 'ColumnModel',
56779 dataIndex : 'weekday0',
56781 renderer : cellRender
56784 xtype: 'ColumnModel',
56786 dataIndex : 'weekday1',
56788 renderer : cellRender
56791 xtype: 'ColumnModel',
56793 dataIndex : 'weekday2',
56794 header : 'Tuesday',
56795 renderer : cellRender
56798 xtype: 'ColumnModel',
56800 dataIndex : 'weekday3',
56801 header : 'Wednesday',
56802 renderer : cellRender
56805 xtype: 'ColumnModel',
56807 dataIndex : 'weekday4',
56808 header : 'Thursday',
56809 renderer : cellRender
56812 xtype: 'ColumnModel',
56814 dataIndex : 'weekday5',
56816 renderer : cellRender
56819 xtype: 'ColumnModel',
56821 dataIndex : 'weekday6',
56822 header : 'Saturday',
56823 renderer : cellRender
56826 this.cm = this.colModel;
56827 this.cm.xmodule = this.xmodule || false;
56831 //this.selModel = new Roo.grid.CellSelectionModel();
56832 //this.sm = this.selModel;
56833 //this.selModel.init(this);
56837 this.container.setWidth(this.width);
56841 this.container.setHeight(this.height);
56848 * The raw click event for the entire grid.
56849 * @param {Roo.EventObject} e
56854 * The raw dblclick event for the entire grid.
56855 * @param {Roo.EventObject} e
56859 * @event contextmenu
56860 * The raw contextmenu event for the entire grid.
56861 * @param {Roo.EventObject} e
56863 "contextmenu" : true,
56866 * The raw mousedown event for the entire grid.
56867 * @param {Roo.EventObject} e
56869 "mousedown" : true,
56872 * The raw mouseup event for the entire grid.
56873 * @param {Roo.EventObject} e
56878 * The raw mouseover event for the entire grid.
56879 * @param {Roo.EventObject} e
56881 "mouseover" : true,
56884 * The raw mouseout event for the entire grid.
56885 * @param {Roo.EventObject} e
56890 * The raw keypress event for the entire grid.
56891 * @param {Roo.EventObject} e
56896 * The raw keydown event for the entire grid.
56897 * @param {Roo.EventObject} e
56905 * Fires when a cell is clicked
56906 * @param {Grid} this
56907 * @param {Number} rowIndex
56908 * @param {Number} columnIndex
56909 * @param {Roo.EventObject} e
56911 "cellclick" : true,
56913 * @event celldblclick
56914 * Fires when a cell is double clicked
56915 * @param {Grid} this
56916 * @param {Number} rowIndex
56917 * @param {Number} columnIndex
56918 * @param {Roo.EventObject} e
56920 "celldblclick" : true,
56923 * Fires when a row is clicked
56924 * @param {Grid} this
56925 * @param {Number} rowIndex
56926 * @param {Roo.EventObject} e
56930 * @event rowdblclick
56931 * Fires when a row is double clicked
56932 * @param {Grid} this
56933 * @param {Number} rowIndex
56934 * @param {Roo.EventObject} e
56936 "rowdblclick" : true,
56938 * @event headerclick
56939 * Fires when a header is clicked
56940 * @param {Grid} this
56941 * @param {Number} columnIndex
56942 * @param {Roo.EventObject} e
56944 "headerclick" : true,
56946 * @event headerdblclick
56947 * Fires when a header cell is double clicked
56948 * @param {Grid} this
56949 * @param {Number} columnIndex
56950 * @param {Roo.EventObject} e
56952 "headerdblclick" : true,
56954 * @event rowcontextmenu
56955 * Fires when a row is right clicked
56956 * @param {Grid} this
56957 * @param {Number} rowIndex
56958 * @param {Roo.EventObject} e
56960 "rowcontextmenu" : true,
56962 * @event cellcontextmenu
56963 * Fires when a cell is right clicked
56964 * @param {Grid} this
56965 * @param {Number} rowIndex
56966 * @param {Number} cellIndex
56967 * @param {Roo.EventObject} e
56969 "cellcontextmenu" : true,
56971 * @event headercontextmenu
56972 * Fires when a header is right clicked
56973 * @param {Grid} this
56974 * @param {Number} columnIndex
56975 * @param {Roo.EventObject} e
56977 "headercontextmenu" : true,
56979 * @event bodyscroll
56980 * Fires when the body element is scrolled
56981 * @param {Number} scrollLeft
56982 * @param {Number} scrollTop
56984 "bodyscroll" : true,
56986 * @event columnresize
56987 * Fires when the user resizes a column
56988 * @param {Number} columnIndex
56989 * @param {Number} newSize
56991 "columnresize" : true,
56993 * @event columnmove
56994 * Fires when the user moves a column
56995 * @param {Number} oldIndex
56996 * @param {Number} newIndex
56998 "columnmove" : true,
57001 * Fires when row(s) start being dragged
57002 * @param {Grid} this
57003 * @param {Roo.GridDD} dd The drag drop object
57004 * @param {event} e The raw browser event
57006 "startdrag" : true,
57009 * Fires when a drag operation is complete
57010 * @param {Grid} this
57011 * @param {Roo.GridDD} dd The drag drop object
57012 * @param {event} e The raw browser event
57017 * Fires when dragged row(s) are dropped on a valid DD target
57018 * @param {Grid} this
57019 * @param {Roo.GridDD} dd The drag drop object
57020 * @param {String} targetId The target drag drop object
57021 * @param {event} e The raw browser event
57026 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57027 * @param {Grid} this
57028 * @param {Roo.GridDD} dd The drag drop object
57029 * @param {String} targetId The target drag drop object
57030 * @param {event} e The raw browser event
57035 * Fires when the dragged row(s) first cross another DD target while being dragged
57036 * @param {Grid} this
57037 * @param {Roo.GridDD} dd The drag drop object
57038 * @param {String} targetId The target drag drop object
57039 * @param {event} e The raw browser event
57041 "dragenter" : true,
57044 * Fires when the dragged row(s) leave another DD target while being dragged
57045 * @param {Grid} this
57046 * @param {Roo.GridDD} dd The drag drop object
57047 * @param {String} targetId The target drag drop object
57048 * @param {event} e The raw browser event
57053 * Fires when a row is rendered, so you can change add a style to it.
57054 * @param {GridView} gridview The grid view
57055 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57061 * Fires when the grid is rendered
57062 * @param {Grid} grid
57067 * Fires when a date is selected
57068 * @param {DatePicker} this
57069 * @param {Date} date The selected date
57073 * @event monthchange
57074 * Fires when the displayed month changes
57075 * @param {DatePicker} this
57076 * @param {Date} date The selected month
57078 'monthchange': true,
57080 * @event evententer
57081 * Fires when mouse over an event
57082 * @param {Calendar} this
57083 * @param {event} Event
57085 'evententer': true,
57087 * @event eventleave
57088 * Fires when the mouse leaves an
57089 * @param {Calendar} this
57092 'eventleave': true,
57094 * @event eventclick
57095 * Fires when the mouse click an
57096 * @param {Calendar} this
57099 'eventclick': true,
57101 * @event eventrender
57102 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
57103 * @param {Calendar} this
57104 * @param {data} data to be modified
57106 'eventrender': true
57110 Roo.grid.Grid.superclass.constructor.call(this);
57111 this.on('render', function() {
57112 this.view.el.addClass('x-grid-cal');
57114 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
57118 if (!Roo.grid.Calendar.style) {
57119 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
57122 '.x-grid-cal .x-grid-col' : {
57123 height: 'auto !important',
57124 'vertical-align': 'top'
57126 '.x-grid-cal .fc-event-hori' : {
57137 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
57139 * @cfg {Store} eventStore The store that loads events.
57144 activeDate : false,
57147 monitorWindowResize : false,
57150 resizeColumns : function() {
57151 var col = (this.view.el.getWidth() / 7) - 3;
57152 // loop through cols, and setWidth
57153 for(var i =0 ; i < 7 ; i++){
57154 this.cm.setColumnWidth(i, col);
57157 setDate :function(date) {
57159 Roo.log('setDate?');
57161 this.resizeColumns();
57162 var vd = this.activeDate;
57163 this.activeDate = date;
57164 // if(vd && this.el){
57165 // var t = date.getTime();
57166 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57167 // Roo.log('using add remove');
57169 // this.fireEvent('monthchange', this, date);
57171 // this.cells.removeClass("fc-state-highlight");
57172 // this.cells.each(function(c){
57173 // if(c.dateValue == t){
57174 // c.addClass("fc-state-highlight");
57175 // setTimeout(function(){
57176 // try{c.dom.firstChild.focus();}catch(e){}
57186 var days = date.getDaysInMonth();
57188 var firstOfMonth = date.getFirstDateOfMonth();
57189 var startingPos = firstOfMonth.getDay()-this.startDay;
57191 if(startingPos < this.startDay){
57195 var pm = date.add(Date.MONTH, -1);
57196 var prevStart = pm.getDaysInMonth()-startingPos;
57200 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57202 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57203 //this.cells.addClassOnOver('fc-state-hover');
57205 var cells = this.cells.elements;
57206 var textEls = this.textNodes;
57208 //Roo.each(cells, function(cell){
57209 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57212 days += startingPos;
57214 // convert everything to numbers so it's fast
57215 var day = 86400000;
57216 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57219 //Roo.log(prevStart);
57221 var today = new Date().clearTime().getTime();
57222 var sel = date.clearTime().getTime();
57223 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57224 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57225 var ddMatch = this.disabledDatesRE;
57226 var ddText = this.disabledDatesText;
57227 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57228 var ddaysText = this.disabledDaysText;
57229 var format = this.format;
57231 var setCellClass = function(cal, cell){
57233 //Roo.log('set Cell Class');
57235 var t = d.getTime();
57240 cell.dateValue = t;
57242 cell.className += " fc-today";
57243 cell.className += " fc-state-highlight";
57244 cell.title = cal.todayText;
57247 // disable highlight in other month..
57248 cell.className += " fc-state-highlight";
57253 //cell.className = " fc-state-disabled";
57254 cell.title = cal.minText;
57258 //cell.className = " fc-state-disabled";
57259 cell.title = cal.maxText;
57263 if(ddays.indexOf(d.getDay()) != -1){
57264 // cell.title = ddaysText;
57265 // cell.className = " fc-state-disabled";
57268 if(ddMatch && format){
57269 var fvalue = d.dateFormat(format);
57270 if(ddMatch.test(fvalue)){
57271 cell.title = ddText.replace("%0", fvalue);
57272 cell.className = " fc-state-disabled";
57276 if (!cell.initialClassName) {
57277 cell.initialClassName = cell.dom.className;
57280 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57285 for(; i < startingPos; i++) {
57286 cells[i].dayName = (++prevStart);
57287 Roo.log(textEls[i]);
57288 d.setDate(d.getDate()+1);
57290 //cells[i].className = "fc-past fc-other-month";
57291 setCellClass(this, cells[i]);
57296 for(; i < days; i++){
57297 intDay = i - startingPos + 1;
57298 cells[i].dayName = (intDay);
57299 d.setDate(d.getDate()+1);
57301 cells[i].className = ''; // "x-date-active";
57302 setCellClass(this, cells[i]);
57306 for(; i < 42; i++) {
57307 //textEls[i].innerHTML = (++extraDays);
57309 d.setDate(d.getDate()+1);
57310 cells[i].dayName = (++extraDays);
57311 cells[i].className = "fc-future fc-other-month";
57312 setCellClass(this, cells[i]);
57315 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57317 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57319 // this will cause all the cells to mis
57322 for (var r = 0;r < 6;r++) {
57323 for (var c =0;c < 7;c++) {
57324 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57328 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57329 for(i=0;i<cells.length;i++) {
57331 this.cells.elements[i].dayName = cells[i].dayName ;
57332 this.cells.elements[i].className = cells[i].className;
57333 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57334 this.cells.elements[i].title = cells[i].title ;
57335 this.cells.elements[i].dateValue = cells[i].dateValue ;
57341 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57342 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57344 ////if(totalRows != 6){
57345 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57346 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57349 this.fireEvent('monthchange', this, date);
57354 * Returns the grid's SelectionModel.
57355 * @return {SelectionModel}
57357 getSelectionModel : function(){
57358 if(!this.selModel){
57359 this.selModel = new Roo.grid.CellSelectionModel();
57361 return this.selModel;
57365 this.eventStore.load()
57371 findCell : function(dt) {
57372 dt = dt.clearTime().getTime();
57374 this.cells.each(function(c){
57375 //Roo.log("check " +c.dateValue + '?=' + dt);
57376 if(c.dateValue == dt){
57386 findCells : function(rec) {
57387 var s = rec.data.start_dt.clone().clearTime().getTime();
57389 var e= rec.data.end_dt.clone().clearTime().getTime();
57392 this.cells.each(function(c){
57393 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57395 if(c.dateValue > e){
57398 if(c.dateValue < s){
57407 findBestRow: function(cells)
57411 for (var i =0 ; i < cells.length;i++) {
57412 ret = Math.max(cells[i].rows || 0,ret);
57419 addItem : function(rec)
57421 // look for vertical location slot in
57422 var cells = this.findCells(rec);
57424 rec.row = this.findBestRow(cells);
57426 // work out the location.
57430 for(var i =0; i < cells.length; i++) {
57438 if (crow.start.getY() == cells[i].getY()) {
57440 crow.end = cells[i];
57456 for (var i = 0; i < cells.length;i++) {
57457 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57464 clearEvents: function() {
57466 if (!this.eventStore.getCount()) {
57469 // reset number of rows in cells.
57470 Roo.each(this.cells.elements, function(c){
57474 this.eventStore.each(function(e) {
57475 this.clearEvent(e);
57480 clearEvent : function(ev)
57483 Roo.each(ev.els, function(el) {
57484 el.un('mouseenter' ,this.onEventEnter, this);
57485 el.un('mouseleave' ,this.onEventLeave, this);
57493 renderEvent : function(ev,ctr) {
57495 ctr = this.view.el.select('.fc-event-container',true).first();
57499 this.clearEvent(ev);
57505 var cells = ev.cells;
57506 var rows = ev.rows;
57507 this.fireEvent('eventrender', this, ev);
57509 for(var i =0; i < rows.length; i++) {
57513 cls += ' fc-event-start';
57515 if ((i+1) == rows.length) {
57516 cls += ' fc-event-end';
57519 //Roo.log(ev.data);
57520 // how many rows should it span..
57521 var cg = this.eventTmpl.append(ctr,Roo.apply({
57524 }, ev.data) , true);
57527 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57528 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57529 cg.on('click', this.onEventClick, this, ev);
57533 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57534 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57537 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57538 cg.setWidth(ebox.right - sbox.x -2);
57542 renderEvents: function()
57544 // first make sure there is enough space..
57546 if (!this.eventTmpl) {
57547 this.eventTmpl = new Roo.Template(
57548 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57549 '<div class="fc-event-inner">' +
57550 '<span class="fc-event-time">{time}</span>' +
57551 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57553 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57561 this.cells.each(function(c) {
57562 //Roo.log(c.select('.fc-day-content div',true).first());
57563 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57566 var ctr = this.view.el.select('.fc-event-container',true).first();
57569 this.eventStore.each(function(ev){
57571 this.renderEvent(ev);
57575 this.view.layout();
57579 onEventEnter: function (e, el,event,d) {
57580 this.fireEvent('evententer', this, el, event);
57583 onEventLeave: function (e, el,event,d) {
57584 this.fireEvent('eventleave', this, el, event);
57587 onEventClick: function (e, el,event,d) {
57588 this.fireEvent('eventclick', this, el, event);
57591 onMonthChange: function () {
57595 onLoad: function () {
57597 //Roo.log('calendar onload');
57599 if(this.eventStore.getCount() > 0){
57603 this.eventStore.each(function(d){
57608 if (typeof(add.end_dt) == 'undefined') {
57609 Roo.log("Missing End time in calendar data: ");
57613 if (typeof(add.start_dt) == 'undefined') {
57614 Roo.log("Missing Start time in calendar data: ");
57618 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
57619 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
57620 add.id = add.id || d.id;
57621 add.title = add.title || '??';
57629 this.renderEvents();
57639 render : function ()
57643 if (!this.view.el.hasClass('course-timesheet')) {
57644 this.view.el.addClass('course-timesheet');
57646 if (this.tsStyle) {
57651 Roo.log(_this.grid.view.el.getWidth());
57654 this.tsStyle = Roo.util.CSS.createStyleSheet({
57655 '.course-timesheet .x-grid-row' : {
57658 '.x-grid-row td' : {
57659 'vertical-align' : 0
57661 '.course-edit-link' : {
57663 'text-overflow' : 'ellipsis',
57664 'overflow' : 'hidden',
57665 'white-space' : 'nowrap',
57666 'cursor' : 'pointer'
57671 '.de-act-sup-link' : {
57672 'color' : 'purple',
57673 'text-decoration' : 'line-through'
57677 'text-decoration' : 'line-through'
57679 '.course-timesheet .course-highlight' : {
57680 'border-top-style': 'dashed !important',
57681 'border-bottom-bottom': 'dashed !important'
57683 '.course-timesheet .course-item' : {
57684 'font-family' : 'tahoma, arial, helvetica',
57685 'font-size' : '11px',
57686 'overflow' : 'hidden',
57687 'padding-left' : '10px',
57688 'padding-right' : '10px',
57689 'padding-top' : '10px'
57697 monitorWindowResize : false,
57698 cellrenderer : function(v,x,r)
57703 xtype: 'CellSelectionModel',
57710 beforeload : function (_self, options)
57712 options.params = options.params || {};
57713 options.params._month = _this.monthField.getValue();
57714 options.params.limit = 9999;
57715 options.params['sort'] = 'when_dt';
57716 options.params['dir'] = 'ASC';
57717 this.proxy.loadResponse = this.loadResponse;
57719 //this.addColumns();
57721 load : function (_self, records, options)
57723 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
57724 // if you click on the translation.. you can edit it...
57725 var el = Roo.get(this);
57726 var id = el.dom.getAttribute('data-id');
57727 var d = el.dom.getAttribute('data-date');
57728 var t = el.dom.getAttribute('data-time');
57729 //var id = this.child('span').dom.textContent;
57732 Pman.Dialog.CourseCalendar.show({
57736 productitem_active : id ? 1 : 0
57738 _this.grid.ds.load({});
57743 _this.panel.fireEvent('resize', [ '', '' ]);
57746 loadResponse : function(o, success, response){
57747 // this is overridden on before load..
57749 Roo.log("our code?");
57750 //Roo.log(success);
57751 //Roo.log(response)
57752 delete this.activeRequest;
57754 this.fireEvent("loadexception", this, o, response);
57755 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57760 result = o.reader.read(response);
57762 Roo.log("load exception?");
57763 this.fireEvent("loadexception", this, o, response, e);
57764 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57767 Roo.log("ready...");
57768 // loop through result.records;
57769 // and set this.tdate[date] = [] << array of records..
57771 Roo.each(result.records, function(r){
57773 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
57774 _this.tdata[r.data.when_dt.format('j')] = [];
57776 _this.tdata[r.data.when_dt.format('j')].push(r.data);
57779 //Roo.log(_this.tdata);
57781 result.records = [];
57782 result.totalRecords = 6;
57784 // let's generate some duumy records for the rows.
57785 //var st = _this.dateField.getValue();
57787 // work out monday..
57788 //st = st.add(Date.DAY, -1 * st.format('w'));
57790 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57792 var firstOfMonth = date.getFirstDayOfMonth();
57793 var days = date.getDaysInMonth();
57795 var firstAdded = false;
57796 for (var i = 0; i < result.totalRecords ; i++) {
57797 //var d= st.add(Date.DAY, i);
57800 for(var w = 0 ; w < 7 ; w++){
57801 if(!firstAdded && firstOfMonth != w){
57808 var dd = (d > 0 && d < 10) ? "0"+d : d;
57809 row['weekday'+w] = String.format(
57810 '<span style="font-size: 16px;"><b>{0}</b></span>'+
57811 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
57813 date.format('Y-m-')+dd
57816 if(typeof(_this.tdata[d]) != 'undefined'){
57817 Roo.each(_this.tdata[d], function(r){
57821 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
57822 if(r.parent_id*1>0){
57823 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
57826 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
57827 deactive = 'de-act-link';
57830 row['weekday'+w] += String.format(
57831 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
57833 r.product_id_name, //1
57834 r.when_dt.format('h:ia'), //2
57844 // only do this if something added..
57846 result.records.push(_this.grid.dataSource.reader.newRow(row));
57850 // push it twice. (second one with an hour..
57854 this.fireEvent("load", this, o, o.request.arg);
57855 o.request.callback.call(o.request.scope, result, o.request.arg, true);
57857 sortInfo : {field: 'when_dt', direction : 'ASC' },
57859 xtype: 'HttpProxy',
57862 url : baseURL + '/Roo/Shop_course.php'
57865 xtype: 'JsonReader',
57882 'name': 'parent_id',
57886 'name': 'product_id',
57890 'name': 'productitem_id',
57908 click : function (_self, e)
57910 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57911 sd.setMonth(sd.getMonth()-1);
57912 _this.monthField.setValue(sd.format('Y-m-d'));
57913 _this.grid.ds.load({});
57919 xtype: 'Separator',
57923 xtype: 'MonthField',
57926 render : function (_self)
57928 _this.monthField = _self;
57929 // _this.monthField.set today
57931 select : function (combo, date)
57933 _this.grid.ds.load({});
57936 value : (function() { return new Date(); })()
57939 xtype: 'Separator',
57945 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
57955 click : function (_self, e)
57957 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57958 sd.setMonth(sd.getMonth()+1);
57959 _this.monthField.setValue(sd.format('Y-m-d'));
57960 _this.grid.ds.load({});
57973 * Ext JS Library 1.1.1
57974 * Copyright(c) 2006-2007, Ext JS, LLC.
57976 * Originally Released Under LGPL - original licence link has changed is not relivant.
57979 * <script type="text/javascript">
57983 * @class Roo.LoadMask
57984 * A simple utility class for generically masking elements while loading data. If the element being masked has
57985 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
57986 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
57987 * element's UpdateManager load indicator and will be destroyed after the initial load.
57989 * Create a new LoadMask
57990 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
57991 * @param {Object} config The config object
57993 Roo.LoadMask = function(el, config){
57994 this.el = Roo.get(el);
57995 Roo.apply(this, config);
57997 this.store.on('beforeload', this.onBeforeLoad, this);
57998 this.store.on('load', this.onLoad, this);
57999 this.store.on('loadexception', this.onLoadException, this);
58000 this.removeMask = false;
58002 var um = this.el.getUpdateManager();
58003 um.showLoadIndicator = false; // disable the default indicator
58004 um.on('beforeupdate', this.onBeforeLoad, this);
58005 um.on('update', this.onLoad, this);
58006 um.on('failure', this.onLoad, this);
58007 this.removeMask = true;
58011 Roo.LoadMask.prototype = {
58013 * @cfg {Boolean} removeMask
58014 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
58015 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
58018 * @cfg {String} msg
58019 * The text to display in a centered loading message box (defaults to 'Loading...')
58021 msg : 'Loading...',
58023 * @cfg {String} msgCls
58024 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
58026 msgCls : 'x-mask-loading',
58029 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
58035 * Disables the mask to prevent it from being displayed
58037 disable : function(){
58038 this.disabled = true;
58042 * Enables the mask so that it can be displayed
58044 enable : function(){
58045 this.disabled = false;
58048 onLoadException : function()
58050 Roo.log(arguments);
58052 if (typeof(arguments[3]) != 'undefined') {
58053 Roo.MessageBox.alert("Error loading",arguments[3]);
58057 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
58058 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
58067 this.el.unmask(this.removeMask);
58070 onLoad : function()
58072 this.el.unmask(this.removeMask);
58076 onBeforeLoad : function(){
58077 if(!this.disabled){
58078 this.el.mask(this.msg, this.msgCls);
58083 destroy : function(){
58085 this.store.un('beforeload', this.onBeforeLoad, this);
58086 this.store.un('load', this.onLoad, this);
58087 this.store.un('loadexception', this.onLoadException, this);
58089 var um = this.el.getUpdateManager();
58090 um.un('beforeupdate', this.onBeforeLoad, this);
58091 um.un('update', this.onLoad, this);
58092 um.un('failure', this.onLoad, this);
58097 * Ext JS Library 1.1.1
58098 * Copyright(c) 2006-2007, Ext JS, LLC.
58100 * Originally Released Under LGPL - original licence link has changed is not relivant.
58103 * <script type="text/javascript">
58108 * @class Roo.XTemplate
58109 * @extends Roo.Template
58110 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
58112 var t = new Roo.XTemplate(
58113 '<select name="{name}">',
58114 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
58118 // then append, applying the master template values
58121 * Supported features:
58126 {a_variable} - output encoded.
58127 {a_variable.format:("Y-m-d")} - call a method on the variable
58128 {a_variable:raw} - unencoded output
58129 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
58130 {a_variable:this.method_on_template(...)} - call a method on the template object.
58135 <tpl for="a_variable or condition.."></tpl>
58136 <tpl if="a_variable or condition"></tpl>
58137 <tpl exec="some javascript"></tpl>
58138 <tpl name="named_template"></tpl> (experimental)
58140 <tpl for="."></tpl> - just iterate the property..
58141 <tpl for=".."></tpl> - iterates with the parent (probably the template)
58145 Roo.XTemplate = function()
58147 Roo.XTemplate.superclass.constructor.apply(this, arguments);
58154 Roo.extend(Roo.XTemplate, Roo.Template, {
58157 * The various sub templates
58162 * basic tag replacing syntax
58165 * // you can fake an object call by doing this
58169 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58172 * compile the template
58174 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58177 compile: function()
58181 s = ['<tpl>', s, '</tpl>'].join('');
58183 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58184 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58185 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58186 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58187 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58192 while(true == !!(m = s.match(re))){
58193 var forMatch = m[0].match(nameRe),
58194 ifMatch = m[0].match(ifRe),
58195 execMatch = m[0].match(execRe),
58196 namedMatch = m[0].match(namedRe),
58201 name = forMatch && forMatch[1] ? forMatch[1] : '';
58204 // if - puts fn into test..
58205 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58207 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58212 // exec - calls a function... returns empty if true is returned.
58213 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58215 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58223 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58224 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58225 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58228 var uid = namedMatch ? namedMatch[1] : id;
58232 id: namedMatch ? namedMatch[1] : id,
58239 s = s.replace(m[0], '');
58241 s = s.replace(m[0], '{xtpl'+ id + '}');
58246 for(var i = tpls.length-1; i >= 0; --i){
58247 this.compileTpl(tpls[i]);
58248 this.tpls[tpls[i].id] = tpls[i];
58250 this.master = tpls[tpls.length-1];
58254 * same as applyTemplate, except it's done to one of the subTemplates
58255 * when using named templates, you can do:
58257 * var str = pl.applySubTemplate('your-name', values);
58260 * @param {Number} id of the template
58261 * @param {Object} values to apply to template
58262 * @param {Object} parent (normaly the instance of this object)
58264 applySubTemplate : function(id, values, parent)
58268 var t = this.tpls[id];
58272 if(t.test && !t.test.call(this, values, parent)){
58276 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58277 Roo.log(e.toString());
58283 if(t.exec && t.exec.call(this, values, parent)){
58287 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58288 Roo.log(e.toString());
58293 var vs = t.target ? t.target.call(this, values, parent) : values;
58294 parent = t.target ? values : parent;
58295 if(t.target && vs instanceof Array){
58297 for(var i = 0, len = vs.length; i < len; i++){
58298 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58300 return buf.join('');
58302 return t.compiled.call(this, vs, parent);
58304 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58305 Roo.log(e.toString());
58306 Roo.log(t.compiled);
58311 compileTpl : function(tpl)
58313 var fm = Roo.util.Format;
58314 var useF = this.disableFormats !== true;
58315 var sep = Roo.isGecko ? "+" : ",";
58316 var undef = function(str) {
58317 Roo.log("Property not found :" + str);
58321 var fn = function(m, name, format, args)
58323 //Roo.log(arguments);
58324 args = args ? args.replace(/\\'/g,"'") : args;
58325 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58326 if (typeof(format) == 'undefined') {
58327 format= 'htmlEncode';
58329 if (format == 'raw' ) {
58333 if(name.substr(0, 4) == 'xtpl'){
58334 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58337 // build an array of options to determine if value is undefined..
58339 // basically get 'xxxx.yyyy' then do
58340 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58341 // (function () { Roo.log("Property not found"); return ''; })() :
58346 Roo.each(name.split('.'), function(st) {
58347 lookfor += (lookfor.length ? '.': '') + st;
58348 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58351 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58354 if(format && useF){
58356 args = args ? ',' + args : "";
58358 if(format.substr(0, 5) != "this."){
58359 format = "fm." + format + '(';
58361 format = 'this.call("'+ format.substr(5) + '", ';
58365 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58369 // called with xxyx.yuu:(test,test)
58371 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58373 // raw.. - :raw modifier..
58374 return "'"+ sep + udef_st + name + ")"+sep+"'";
58378 // branched to use + in gecko and [].join() in others
58380 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58381 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58384 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58385 body.push(tpl.body.replace(/(\r\n|\n)/g,
58386 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58387 body.push("'].join('');};};");
58388 body = body.join('');
58391 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58393 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58399 applyTemplate : function(values){
58400 return this.master.compiled.call(this, values, {});
58401 //var s = this.subs;
58404 apply : function(){
58405 return this.applyTemplate.apply(this, arguments);
58410 Roo.XTemplate.from = function(el){
58411 el = Roo.getDom(el);
58412 return new Roo.XTemplate(el.value || el.innerHTML);