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 if (this.disabled) {
40893 this.setChecked(!this.checked);
40895 //if(this.el.dom.checked != this.checked){
40896 // this.setValue(this.el.dom.checked);
40901 * Sets the checked state of the checkbox.
40902 * On is always based on a string comparison between inputValue and the param.
40903 * @param {Boolean/String} value - the value to set
40904 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40906 setValue : function(v,suppressEvent){
40909 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40910 //if(this.el && this.el.dom){
40911 // this.el.dom.checked = this.checked;
40912 // this.el.dom.defaultChecked = this.checked;
40914 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40915 //this.fireEvent("check", this, this.checked);
40918 setChecked : function(state,suppressEvent)
40920 if (this.inSetChecked) {
40921 this.checked = state;
40927 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40929 this.checked = state;
40930 if(suppressEvent !== true){
40931 this.fireEvent('check', this, state);
40933 this.inSetChecked = true;
40934 this.el.dom.value = state ? this.inputValue : this.valueOff;
40935 this.inSetChecked = false;
40938 // handle setting of hidden value by some other method!!?!?
40939 setFromHidden: function()
40944 //console.log("SET FROM HIDDEN");
40945 //alert('setFrom hidden');
40946 this.setValue(this.el.dom.value);
40949 onDestroy : function()
40952 Roo.get(this.viewEl).remove();
40955 Roo.form.Checkbox.superclass.onDestroy.call(this);
40960 * Ext JS Library 1.1.1
40961 * Copyright(c) 2006-2007, Ext JS, LLC.
40963 * Originally Released Under LGPL - original licence link has changed is not relivant.
40966 * <script type="text/javascript">
40970 * @class Roo.form.Radio
40971 * @extends Roo.form.Checkbox
40972 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40973 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40975 * Creates a new Radio
40976 * @param {Object} config Configuration options
40978 Roo.form.Radio = function(){
40979 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40981 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40982 inputType: 'radio',
40985 * If this radio is part of a group, it will return the selected value
40988 getGroupValue : function(){
40989 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40993 onRender : function(ct, position){
40994 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40996 if(this.inputValue !== undefined){
40997 this.el.dom.value = this.inputValue;
41000 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41001 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41002 //var viewEl = this.wrap.createChild({
41003 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41004 //this.viewEl = viewEl;
41005 //this.wrap.on('click', this.onClick, this);
41007 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41008 //this.el.on('propertychange', this.setFromHidden, this); //ie
41013 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41014 // viewEl.on('click', this.onClick, this);
41017 this.el.dom.checked = 'checked' ;
41023 });//<script type="text/javascript">
41026 * Based Ext JS Library 1.1.1
41027 * Copyright(c) 2006-2007, Ext JS, LLC.
41033 * @class Roo.HtmlEditorCore
41034 * @extends Roo.Component
41035 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41037 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41040 Roo.HtmlEditorCore = function(config){
41043 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41048 * @event initialize
41049 * Fires when the editor is fully initialized (including the iframe)
41050 * @param {Roo.HtmlEditorCore} this
41055 * Fires when the editor is first receives the focus. Any insertion must wait
41056 * until after this event.
41057 * @param {Roo.HtmlEditorCore} this
41061 * @event beforesync
41062 * Fires before the textarea is updated with content from the editor iframe. Return false
41063 * to cancel the sync.
41064 * @param {Roo.HtmlEditorCore} this
41065 * @param {String} html
41069 * @event beforepush
41070 * Fires before the iframe editor is updated with content from the textarea. Return false
41071 * to cancel the push.
41072 * @param {Roo.HtmlEditorCore} this
41073 * @param {String} html
41078 * Fires when the textarea is updated with content from the editor iframe.
41079 * @param {Roo.HtmlEditorCore} this
41080 * @param {String} html
41085 * Fires when the iframe editor is updated with content from the textarea.
41086 * @param {Roo.HtmlEditorCore} this
41087 * @param {String} html
41092 * @event editorevent
41093 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41094 * @param {Roo.HtmlEditorCore} this
41099 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
41101 // defaults : white / black...
41102 this.applyBlacklists();
41109 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41113 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41119 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41124 * @cfg {Number} height (in pixels)
41128 * @cfg {Number} width (in pixels)
41133 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41136 stylesheets: false,
41141 // private properties
41142 validationEvent : false,
41144 initialized : false,
41146 sourceEditMode : false,
41147 onFocus : Roo.emptyFn,
41149 hideMode:'offsets',
41153 // blacklist + whitelisted elements..
41160 * Protected method that will not generally be called directly. It
41161 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41162 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41164 getDocMarkup : function(){
41167 Roo.log(this.stylesheets);
41169 // inherit styels from page...??
41170 if (this.stylesheets === false) {
41172 Roo.get(document.head).select('style').each(function(node) {
41173 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41176 Roo.get(document.head).select('link').each(function(node) {
41177 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41180 } else if (!this.stylesheets.length) {
41182 st = '<style type="text/css">' +
41183 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41186 Roo.each(this.stylesheets, function(s) {
41187 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
41192 st += '<style type="text/css">' +
41193 'IMG { cursor: pointer } ' +
41197 return '<html><head>' + st +
41198 //<style type="text/css">' +
41199 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41201 ' </head><body class="roo-htmleditor-body"></body></html>';
41205 onRender : function(ct, position)
41208 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41209 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41212 this.el.dom.style.border = '0 none';
41213 this.el.dom.setAttribute('tabIndex', -1);
41214 this.el.addClass('x-hidden hide');
41218 if(Roo.isIE){ // fix IE 1px bogus margin
41219 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41223 this.frameId = Roo.id();
41227 var iframe = this.owner.wrap.createChild({
41229 cls: 'form-control', // bootstrap..
41231 name: this.frameId,
41232 frameBorder : 'no',
41233 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41238 this.iframe = iframe.dom;
41240 this.assignDocWin();
41242 this.doc.designMode = 'on';
41245 this.doc.write(this.getDocMarkup());
41249 var task = { // must defer to wait for browser to be ready
41251 //console.log("run task?" + this.doc.readyState);
41252 this.assignDocWin();
41253 if(this.doc.body || this.doc.readyState == 'complete'){
41255 this.doc.designMode="on";
41259 Roo.TaskMgr.stop(task);
41260 this.initEditor.defer(10, this);
41267 Roo.TaskMgr.start(task);
41274 onResize : function(w, h)
41276 Roo.log('resize: ' +w + ',' + h );
41277 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41281 if(typeof w == 'number'){
41283 this.iframe.style.width = w + 'px';
41285 if(typeof h == 'number'){
41287 this.iframe.style.height = h + 'px';
41289 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41296 * Toggles the editor between standard and source edit mode.
41297 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41299 toggleSourceEdit : function(sourceEditMode){
41301 this.sourceEditMode = sourceEditMode === true;
41303 if(this.sourceEditMode){
41305 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41308 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41309 //this.iframe.className = '';
41312 //this.setSize(this.owner.wrap.getSize());
41313 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41320 * Protected method that will not generally be called directly. If you need/want
41321 * custom HTML cleanup, this is the method you should override.
41322 * @param {String} html The HTML to be cleaned
41323 * return {String} The cleaned HTML
41325 cleanHtml : function(html){
41326 html = String(html);
41327 if(html.length > 5){
41328 if(Roo.isSafari){ // strip safari nonsense
41329 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41332 if(html == ' '){
41339 * HTML Editor -> Textarea
41340 * Protected method that will not generally be called directly. Syncs the contents
41341 * of the editor iframe with the textarea.
41343 syncValue : function(){
41344 if(this.initialized){
41345 var bd = (this.doc.body || this.doc.documentElement);
41346 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41347 var html = bd.innerHTML;
41349 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41350 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41352 html = '<div style="'+m[0]+'">' + html + '</div>';
41355 html = this.cleanHtml(html);
41356 // fix up the special chars.. normaly like back quotes in word...
41357 // however we do not want to do this with chinese..
41358 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41359 var cc = b.charCodeAt();
41361 (cc >= 0x4E00 && cc < 0xA000 ) ||
41362 (cc >= 0x3400 && cc < 0x4E00 ) ||
41363 (cc >= 0xf900 && cc < 0xfb00 )
41369 if(this.owner.fireEvent('beforesync', this, html) !== false){
41370 this.el.dom.value = html;
41371 this.owner.fireEvent('sync', this, html);
41377 * Protected method that will not generally be called directly. Pushes the value of the textarea
41378 * into the iframe editor.
41380 pushValue : function(){
41381 if(this.initialized){
41382 var v = this.el.dom.value.trim();
41384 // if(v.length < 1){
41388 if(this.owner.fireEvent('beforepush', this, v) !== false){
41389 var d = (this.doc.body || this.doc.documentElement);
41391 this.cleanUpPaste();
41392 this.el.dom.value = d.innerHTML;
41393 this.owner.fireEvent('push', this, v);
41399 deferFocus : function(){
41400 this.focus.defer(10, this);
41404 focus : function(){
41405 if(this.win && !this.sourceEditMode){
41412 assignDocWin: function()
41414 var iframe = this.iframe;
41417 this.doc = iframe.contentWindow.document;
41418 this.win = iframe.contentWindow;
41420 // if (!Roo.get(this.frameId)) {
41423 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41424 // this.win = Roo.get(this.frameId).dom.contentWindow;
41426 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
41430 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41431 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
41436 initEditor : function(){
41437 //console.log("INIT EDITOR");
41438 this.assignDocWin();
41442 this.doc.designMode="on";
41444 this.doc.write(this.getDocMarkup());
41447 var dbody = (this.doc.body || this.doc.documentElement);
41448 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41449 // this copies styles from the containing element into thsi one..
41450 // not sure why we need all of this..
41451 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41453 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41454 //ss['background-attachment'] = 'fixed'; // w3c
41455 dbody.bgProperties = 'fixed'; // ie
41456 //Roo.DomHelper.applyStyles(dbody, ss);
41457 Roo.EventManager.on(this.doc, {
41458 //'mousedown': this.onEditorEvent,
41459 'mouseup': this.onEditorEvent,
41460 'dblclick': this.onEditorEvent,
41461 'click': this.onEditorEvent,
41462 'keyup': this.onEditorEvent,
41467 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41469 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41470 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41472 this.initialized = true;
41474 this.owner.fireEvent('initialize', this);
41479 onDestroy : function(){
41485 //for (var i =0; i < this.toolbars.length;i++) {
41486 // // fixme - ask toolbars for heights?
41487 // this.toolbars[i].onDestroy();
41490 //this.wrap.dom.innerHTML = '';
41491 //this.wrap.remove();
41496 onFirstFocus : function(){
41498 this.assignDocWin();
41501 this.activated = true;
41504 if(Roo.isGecko){ // prevent silly gecko errors
41506 var s = this.win.getSelection();
41507 if(!s.focusNode || s.focusNode.nodeType != 3){
41508 var r = s.getRangeAt(0);
41509 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41514 this.execCmd('useCSS', true);
41515 this.execCmd('styleWithCSS', false);
41518 this.owner.fireEvent('activate', this);
41522 adjustFont: function(btn){
41523 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41524 //if(Roo.isSafari){ // safari
41527 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41528 if(Roo.isSafari){ // safari
41529 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41530 v = (v < 10) ? 10 : v;
41531 v = (v > 48) ? 48 : v;
41532 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41537 v = Math.max(1, v+adjust);
41539 this.execCmd('FontSize', v );
41542 onEditorEvent : function(e){
41543 this.owner.fireEvent('editorevent', this, e);
41544 // this.updateToolbar();
41545 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41548 insertTag : function(tg)
41550 // could be a bit smarter... -> wrap the current selected tRoo..
41551 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41553 range = this.createRange(this.getSelection());
41554 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41555 wrappingNode.appendChild(range.extractContents());
41556 range.insertNode(wrappingNode);
41563 this.execCmd("formatblock", tg);
41567 insertText : function(txt)
41571 var range = this.createRange();
41572 range.deleteContents();
41573 //alert(Sender.getAttribute('label'));
41575 range.insertNode(this.doc.createTextNode(txt));
41581 * Executes a Midas editor command on the editor document and performs necessary focus and
41582 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41583 * @param {String} cmd The Midas command
41584 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41586 relayCmd : function(cmd, value){
41588 this.execCmd(cmd, value);
41589 this.owner.fireEvent('editorevent', this);
41590 //this.updateToolbar();
41591 this.owner.deferFocus();
41595 * Executes a Midas editor command directly on the editor document.
41596 * For visual commands, you should use {@link #relayCmd} instead.
41597 * <b>This should only be called after the editor is initialized.</b>
41598 * @param {String} cmd The Midas command
41599 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41601 execCmd : function(cmd, value){
41602 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41609 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41611 * @param {String} text | dom node..
41613 insertAtCursor : function(text)
41618 if(!this.activated){
41624 var r = this.doc.selection.createRange();
41635 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41639 // from jquery ui (MIT licenced)
41641 var win = this.win;
41643 if (win.getSelection && win.getSelection().getRangeAt) {
41644 range = win.getSelection().getRangeAt(0);
41645 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41646 range.insertNode(node);
41647 } else if (win.document.selection && win.document.selection.createRange) {
41648 // no firefox support
41649 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41650 win.document.selection.createRange().pasteHTML(txt);
41652 // no firefox support
41653 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41654 this.execCmd('InsertHTML', txt);
41663 mozKeyPress : function(e){
41665 var c = e.getCharCode(), cmd;
41668 c = String.fromCharCode(c).toLowerCase();
41682 this.cleanUpPaste.defer(100, this);
41690 e.preventDefault();
41698 fixKeys : function(){ // load time branching for fastest keydown performance
41700 return function(e){
41701 var k = e.getKey(), r;
41704 r = this.doc.selection.createRange();
41707 r.pasteHTML('    ');
41714 r = this.doc.selection.createRange();
41716 var target = r.parentElement();
41717 if(!target || target.tagName.toLowerCase() != 'li'){
41719 r.pasteHTML('<br />');
41725 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41726 this.cleanUpPaste.defer(100, this);
41732 }else if(Roo.isOpera){
41733 return function(e){
41734 var k = e.getKey();
41738 this.execCmd('InsertHTML','    ');
41741 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41742 this.cleanUpPaste.defer(100, this);
41747 }else if(Roo.isSafari){
41748 return function(e){
41749 var k = e.getKey();
41753 this.execCmd('InsertText','\t');
41757 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41758 this.cleanUpPaste.defer(100, this);
41766 getAllAncestors: function()
41768 var p = this.getSelectedNode();
41771 a.push(p); // push blank onto stack..
41772 p = this.getParentElement();
41776 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41780 a.push(this.doc.body);
41784 lastSelNode : false,
41787 getSelection : function()
41789 this.assignDocWin();
41790 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41793 getSelectedNode: function()
41795 // this may only work on Gecko!!!
41797 // should we cache this!!!!
41802 var range = this.createRange(this.getSelection()).cloneRange();
41805 var parent = range.parentElement();
41807 var testRange = range.duplicate();
41808 testRange.moveToElementText(parent);
41809 if (testRange.inRange(range)) {
41812 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41815 parent = parent.parentElement;
41820 // is ancestor a text element.
41821 var ac = range.commonAncestorContainer;
41822 if (ac.nodeType == 3) {
41823 ac = ac.parentNode;
41826 var ar = ac.childNodes;
41829 var other_nodes = [];
41830 var has_other_nodes = false;
41831 for (var i=0;i<ar.length;i++) {
41832 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41835 // fullly contained node.
41837 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41842 // probably selected..
41843 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41844 other_nodes.push(ar[i]);
41848 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41853 has_other_nodes = true;
41855 if (!nodes.length && other_nodes.length) {
41856 nodes= other_nodes;
41858 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41864 createRange: function(sel)
41866 // this has strange effects when using with
41867 // top toolbar - not sure if it's a great idea.
41868 //this.editor.contentWindow.focus();
41869 if (typeof sel != "undefined") {
41871 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41873 return this.doc.createRange();
41876 return this.doc.createRange();
41879 getParentElement: function()
41882 this.assignDocWin();
41883 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41885 var range = this.createRange(sel);
41888 var p = range.commonAncestorContainer;
41889 while (p.nodeType == 3) { // text node
41900 * Range intersection.. the hard stuff...
41904 * [ -- selected range --- ]
41908 * if end is before start or hits it. fail.
41909 * if start is after end or hits it fail.
41911 * if either hits (but other is outside. - then it's not
41917 // @see http://www.thismuchiknow.co.uk/?p=64.
41918 rangeIntersectsNode : function(range, node)
41920 var nodeRange = node.ownerDocument.createRange();
41922 nodeRange.selectNode(node);
41924 nodeRange.selectNodeContents(node);
41927 var rangeStartRange = range.cloneRange();
41928 rangeStartRange.collapse(true);
41930 var rangeEndRange = range.cloneRange();
41931 rangeEndRange.collapse(false);
41933 var nodeStartRange = nodeRange.cloneRange();
41934 nodeStartRange.collapse(true);
41936 var nodeEndRange = nodeRange.cloneRange();
41937 nodeEndRange.collapse(false);
41939 return rangeStartRange.compareBoundaryPoints(
41940 Range.START_TO_START, nodeEndRange) == -1 &&
41941 rangeEndRange.compareBoundaryPoints(
41942 Range.START_TO_START, nodeStartRange) == 1;
41946 rangeCompareNode : function(range, node)
41948 var nodeRange = node.ownerDocument.createRange();
41950 nodeRange.selectNode(node);
41952 nodeRange.selectNodeContents(node);
41956 range.collapse(true);
41958 nodeRange.collapse(true);
41960 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41961 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41963 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41965 var nodeIsBefore = ss == 1;
41966 var nodeIsAfter = ee == -1;
41968 if (nodeIsBefore && nodeIsAfter)
41970 if (!nodeIsBefore && nodeIsAfter)
41971 return 1; //right trailed.
41973 if (nodeIsBefore && !nodeIsAfter)
41974 return 2; // left trailed.
41979 // private? - in a new class?
41980 cleanUpPaste : function()
41982 // cleans up the whole document..
41983 Roo.log('cleanuppaste');
41985 this.cleanUpChildren(this.doc.body);
41986 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41987 if (clean != this.doc.body.innerHTML) {
41988 this.doc.body.innerHTML = clean;
41993 cleanWordChars : function(input) {// change the chars to hex code
41994 var he = Roo.HtmlEditorCore;
41996 var output = input;
41997 Roo.each(he.swapCodes, function(sw) {
41998 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
42000 output = output.replace(swapper, sw[1]);
42007 cleanUpChildren : function (n)
42009 if (!n.childNodes.length) {
42012 for (var i = n.childNodes.length-1; i > -1 ; i--) {
42013 this.cleanUpChild(n.childNodes[i]);
42020 cleanUpChild : function (node)
42023 //console.log(node);
42024 if (node.nodeName == "#text") {
42025 // clean up silly Windows -- stuff?
42028 if (node.nodeName == "#comment") {
42029 node.parentNode.removeChild(node);
42030 // clean up silly Windows -- stuff?
42033 var lcname = node.tagName.toLowerCase();
42034 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
42035 // whitelist of tags..
42037 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
42039 node.parentNode.removeChild(node);
42044 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
42046 // remove <a name=....> as rendering on yahoo mailer is borked with this.
42047 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42049 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42050 // remove_keep_children = true;
42053 if (remove_keep_children) {
42054 this.cleanUpChildren(node);
42055 // inserts everything just before this node...
42056 while (node.childNodes.length) {
42057 var cn = node.childNodes[0];
42058 node.removeChild(cn);
42059 node.parentNode.insertBefore(cn, node);
42061 node.parentNode.removeChild(node);
42065 if (!node.attributes || !node.attributes.length) {
42066 this.cleanUpChildren(node);
42070 function cleanAttr(n,v)
42073 if (v.match(/^\./) || v.match(/^\//)) {
42076 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42079 if (v.match(/^#/)) {
42082 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42083 node.removeAttribute(n);
42087 var cwhite = this.cwhite;
42088 var cblack = this.cblack;
42090 function cleanStyle(n,v)
42092 if (v.match(/expression/)) { //XSS?? should we even bother..
42093 node.removeAttribute(n);
42097 var parts = v.split(/;/);
42100 Roo.each(parts, function(p) {
42101 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42105 var l = p.split(':').shift().replace(/\s+/g,'');
42106 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42108 if ( cwhite.length && cblack.indexOf(l) > -1) {
42109 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42110 //node.removeAttribute(n);
42114 // only allow 'c whitelisted system attributes'
42115 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42116 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42117 //node.removeAttribute(n);
42127 if (clean.length) {
42128 node.setAttribute(n, clean.join(';'));
42130 node.removeAttribute(n);
42136 for (var i = node.attributes.length-1; i > -1 ; i--) {
42137 var a = node.attributes[i];
42140 if (a.name.toLowerCase().substr(0,2)=='on') {
42141 node.removeAttribute(a.name);
42144 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42145 node.removeAttribute(a.name);
42148 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42149 cleanAttr(a.name,a.value); // fixme..
42152 if (a.name == 'style') {
42153 cleanStyle(a.name,a.value);
42156 /// clean up MS crap..
42157 // tecnically this should be a list of valid class'es..
42160 if (a.name == 'class') {
42161 if (a.value.match(/^Mso/)) {
42162 node.className = '';
42165 if (a.value.match(/body/)) {
42166 node.className = '';
42177 this.cleanUpChildren(node);
42182 * Clean up MS wordisms...
42184 cleanWord : function(node)
42187 var cleanWordChildren = function()
42189 if (!node.childNodes.length) {
42192 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42193 _t.cleanWord(node.childNodes[i]);
42199 this.cleanWord(this.doc.body);
42202 if (node.nodeName == "#text") {
42203 // clean up silly Windows -- stuff?
42206 if (node.nodeName == "#comment") {
42207 node.parentNode.removeChild(node);
42208 // clean up silly Windows -- stuff?
42212 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42213 node.parentNode.removeChild(node);
42217 // remove - but keep children..
42218 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42219 while (node.childNodes.length) {
42220 var cn = node.childNodes[0];
42221 node.removeChild(cn);
42222 node.parentNode.insertBefore(cn, node);
42224 node.parentNode.removeChild(node);
42225 cleanWordChildren();
42229 if (node.className.length) {
42231 var cn = node.className.split(/\W+/);
42233 Roo.each(cn, function(cls) {
42234 if (cls.match(/Mso[a-zA-Z]+/)) {
42239 node.className = cna.length ? cna.join(' ') : '';
42241 node.removeAttribute("class");
42245 if (node.hasAttribute("lang")) {
42246 node.removeAttribute("lang");
42249 if (node.hasAttribute("style")) {
42251 var styles = node.getAttribute("style").split(";");
42253 Roo.each(styles, function(s) {
42254 if (!s.match(/:/)) {
42257 var kv = s.split(":");
42258 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42261 // what ever is left... we allow.
42264 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42265 if (!nstyle.length) {
42266 node.removeAttribute('style');
42270 cleanWordChildren();
42274 domToHTML : function(currentElement, depth, nopadtext) {
42276 depth = depth || 0;
42277 nopadtext = nopadtext || false;
42279 if (!currentElement) {
42280 return this.domToHTML(this.doc.body);
42283 //Roo.log(currentElement);
42285 var allText = false;
42286 var nodeName = currentElement.nodeName;
42287 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42289 if (nodeName == '#text') {
42290 return currentElement.nodeValue;
42295 if (nodeName != 'BODY') {
42298 // Prints the node tagName, such as <A>, <IMG>, etc
42301 for(i = 0; i < currentElement.attributes.length;i++) {
42303 var aname = currentElement.attributes.item(i).name;
42304 if (!currentElement.attributes.item(i).value.length) {
42307 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42310 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42319 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42322 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42327 // Traverse the tree
42329 var currentElementChild = currentElement.childNodes.item(i);
42330 var allText = true;
42331 var innerHTML = '';
42333 while (currentElementChild) {
42334 // Formatting code (indent the tree so it looks nice on the screen)
42335 var nopad = nopadtext;
42336 if (lastnode == 'SPAN') {
42340 if (currentElementChild.nodeName == '#text') {
42341 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42342 if (!nopad && toadd.length > 80) {
42343 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42345 innerHTML += toadd;
42348 currentElementChild = currentElement.childNodes.item(i);
42354 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42356 // Recursively traverse the tree structure of the child node
42357 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42358 lastnode = currentElementChild.nodeName;
42360 currentElementChild=currentElement.childNodes.item(i);
42366 // The remaining code is mostly for formatting the tree
42367 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42372 ret+= "</"+tagName+">";
42378 applyBlacklists : function()
42380 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
42381 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
42385 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
42386 if (b.indexOf(tag) > -1) {
42389 this.white.push(tag);
42393 Roo.each(w, function(tag) {
42394 if (b.indexOf(tag) > -1) {
42397 if (this.white.indexOf(tag) > -1) {
42400 this.white.push(tag);
42405 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
42406 if (w.indexOf(tag) > -1) {
42409 this.black.push(tag);
42413 Roo.each(b, function(tag) {
42414 if (w.indexOf(tag) > -1) {
42417 if (this.black.indexOf(tag) > -1) {
42420 this.black.push(tag);
42425 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
42426 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
42430 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
42431 if (b.indexOf(tag) > -1) {
42434 this.cwhite.push(tag);
42438 Roo.each(w, function(tag) {
42439 if (b.indexOf(tag) > -1) {
42442 if (this.cwhite.indexOf(tag) > -1) {
42445 this.cwhite.push(tag);
42450 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
42451 if (w.indexOf(tag) > -1) {
42454 this.cblack.push(tag);
42458 Roo.each(b, function(tag) {
42459 if (w.indexOf(tag) > -1) {
42462 if (this.cblack.indexOf(tag) > -1) {
42465 this.cblack.push(tag);
42470 // hide stuff that is not compatible
42484 * @event specialkey
42488 * @cfg {String} fieldClass @hide
42491 * @cfg {String} focusClass @hide
42494 * @cfg {String} autoCreate @hide
42497 * @cfg {String} inputType @hide
42500 * @cfg {String} invalidClass @hide
42503 * @cfg {String} invalidText @hide
42506 * @cfg {String} msgFx @hide
42509 * @cfg {String} validateOnBlur @hide
42513 Roo.HtmlEditorCore.white = [
42514 'area', 'br', 'img', 'input', 'hr', 'wbr',
42516 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42517 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42518 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42519 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42520 'table', 'ul', 'xmp',
42522 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42525 'dir', 'menu', 'ol', 'ul', 'dl',
42531 Roo.HtmlEditorCore.black = [
42532 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42534 'base', 'basefont', 'bgsound', 'blink', 'body',
42535 'frame', 'frameset', 'head', 'html', 'ilayer',
42536 'iframe', 'layer', 'link', 'meta', 'object',
42537 'script', 'style' ,'title', 'xml' // clean later..
42539 Roo.HtmlEditorCore.clean = [
42540 'script', 'style', 'title', 'xml'
42542 Roo.HtmlEditorCore.remove = [
42547 Roo.HtmlEditorCore.ablack = [
42551 Roo.HtmlEditorCore.aclean = [
42552 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42556 Roo.HtmlEditorCore.pwhite= [
42557 'http', 'https', 'mailto'
42560 // white listed style attributes.
42561 Roo.HtmlEditorCore.cwhite= [
42562 // 'text-align', /// default is to allow most things..
42568 // black listed style attributes.
42569 Roo.HtmlEditorCore.cblack= [
42570 // 'font-size' -- this can be set by the project
42574 Roo.HtmlEditorCore.swapCodes =[
42585 //<script type="text/javascript">
42588 * Ext JS Library 1.1.1
42589 * Copyright(c) 2006-2007, Ext JS, LLC.
42595 Roo.form.HtmlEditor = function(config){
42599 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42601 if (!this.toolbars) {
42602 this.toolbars = [];
42604 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42610 * @class Roo.form.HtmlEditor
42611 * @extends Roo.form.Field
42612 * Provides a lightweight HTML Editor component.
42614 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42616 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42617 * supported by this editor.</b><br/><br/>
42618 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42619 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42621 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42623 * @cfg {Boolean} clearUp
42627 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42632 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42637 * @cfg {Number} height (in pixels)
42641 * @cfg {Number} width (in pixels)
42646 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42649 stylesheets: false,
42653 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
42658 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
42664 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
42669 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
42677 // private properties
42678 validationEvent : false,
42680 initialized : false,
42683 onFocus : Roo.emptyFn,
42685 hideMode:'offsets',
42687 defaultAutoCreate : { // modified by initCompnoent..
42689 style:"width:500px;height:300px;",
42690 autocomplete: "off"
42694 initComponent : function(){
42697 * @event initialize
42698 * Fires when the editor is fully initialized (including the iframe)
42699 * @param {HtmlEditor} this
42704 * Fires when the editor is first receives the focus. Any insertion must wait
42705 * until after this event.
42706 * @param {HtmlEditor} this
42710 * @event beforesync
42711 * Fires before the textarea is updated with content from the editor iframe. Return false
42712 * to cancel the sync.
42713 * @param {HtmlEditor} this
42714 * @param {String} html
42718 * @event beforepush
42719 * Fires before the iframe editor is updated with content from the textarea. Return false
42720 * to cancel the push.
42721 * @param {HtmlEditor} this
42722 * @param {String} html
42727 * Fires when the textarea is updated with content from the editor iframe.
42728 * @param {HtmlEditor} this
42729 * @param {String} html
42734 * Fires when the iframe editor is updated with content from the textarea.
42735 * @param {HtmlEditor} this
42736 * @param {String} html
42740 * @event editmodechange
42741 * Fires when the editor switches edit modes
42742 * @param {HtmlEditor} this
42743 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42745 editmodechange: true,
42747 * @event editorevent
42748 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42749 * @param {HtmlEditor} this
42753 * @event firstfocus
42754 * Fires when on first focus - needed by toolbars..
42755 * @param {HtmlEditor} this
42760 * Auto save the htmlEditor value as a file into Events
42761 * @param {HtmlEditor} this
42765 * @event savedpreview
42766 * preview the saved version of htmlEditor
42767 * @param {HtmlEditor} this
42771 this.defaultAutoCreate = {
42773 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42774 autocomplete: "off"
42779 * Protected method that will not generally be called directly. It
42780 * is called when the editor creates its toolbar. Override this method if you need to
42781 * add custom toolbar buttons.
42782 * @param {HtmlEditor} editor
42784 createToolbar : function(editor){
42785 Roo.log("create toolbars");
42786 if (!editor.toolbars || !editor.toolbars.length) {
42787 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42790 for (var i =0 ; i < editor.toolbars.length;i++) {
42791 editor.toolbars[i] = Roo.factory(
42792 typeof(editor.toolbars[i]) == 'string' ?
42793 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42794 Roo.form.HtmlEditor);
42795 editor.toolbars[i].init(editor);
42803 onRender : function(ct, position)
42806 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
42808 this.wrap = this.el.wrap({
42809 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
42812 this.editorcore.onRender(ct, position);
42814 if (this.resizable) {
42815 this.resizeEl = new Roo.Resizable(this.wrap, {
42819 minHeight : this.height,
42820 height: this.height,
42821 handles : this.resizable,
42824 resize : function(r, w, h) {
42825 _t.onResize(w,h); // -something
42831 this.createToolbar(this);
42835 this.setSize(this.wrap.getSize());
42837 if (this.resizeEl) {
42838 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
42839 // should trigger onReize..
42842 // if(this.autosave && this.w){
42843 // this.autoSaveFn = setInterval(this.autosave, 1000);
42848 onResize : function(w, h)
42850 //Roo.log('resize: ' +w + ',' + h );
42851 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
42856 if(typeof w == 'number'){
42857 var aw = w - this.wrap.getFrameWidth('lr');
42858 this.el.setWidth(this.adjustWidth('textarea', aw));
42861 if(typeof h == 'number'){
42863 for (var i =0; i < this.toolbars.length;i++) {
42864 // fixme - ask toolbars for heights?
42865 tbh += this.toolbars[i].tb.el.getHeight();
42866 if (this.toolbars[i].footer) {
42867 tbh += this.toolbars[i].footer.el.getHeight();
42874 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
42875 ah -= 5; // knock a few pixes off for look..
42876 this.el.setHeight(this.adjustWidth('textarea', ah));
42880 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
42881 this.editorcore.onResize(ew,eh);
42886 * Toggles the editor between standard and source edit mode.
42887 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42889 toggleSourceEdit : function(sourceEditMode)
42891 this.editorcore.toggleSourceEdit(sourceEditMode);
42893 if(this.editorcore.sourceEditMode){
42894 Roo.log('editor - showing textarea');
42897 // Roo.log(this.syncValue());
42898 this.editorcore.syncValue();
42899 this.el.removeClass('x-hidden');
42900 this.el.dom.removeAttribute('tabIndex');
42903 Roo.log('editor - hiding textarea');
42905 // Roo.log(this.pushValue());
42906 this.editorcore.pushValue();
42908 this.el.addClass('x-hidden');
42909 this.el.dom.setAttribute('tabIndex', -1);
42910 //this.deferFocus();
42913 this.setSize(this.wrap.getSize());
42914 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
42917 // private (for BoxComponent)
42918 adjustSize : Roo.BoxComponent.prototype.adjustSize,
42920 // private (for BoxComponent)
42921 getResizeEl : function(){
42925 // private (for BoxComponent)
42926 getPositionEl : function(){
42931 initEvents : function(){
42932 this.originalValue = this.getValue();
42936 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42939 markInvalid : Roo.emptyFn,
42941 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42944 clearInvalid : Roo.emptyFn,
42946 setValue : function(v){
42947 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
42948 this.editorcore.pushValue();
42953 deferFocus : function(){
42954 this.focus.defer(10, this);
42958 focus : function(){
42959 this.editorcore.focus();
42965 onDestroy : function(){
42971 for (var i =0; i < this.toolbars.length;i++) {
42972 // fixme - ask toolbars for heights?
42973 this.toolbars[i].onDestroy();
42976 this.wrap.dom.innerHTML = '';
42977 this.wrap.remove();
42982 onFirstFocus : function(){
42983 //Roo.log("onFirstFocus");
42984 this.editorcore.onFirstFocus();
42985 for (var i =0; i < this.toolbars.length;i++) {
42986 this.toolbars[i].onFirstFocus();
42992 syncValue : function()
42994 this.editorcore.syncValue();
42997 pushValue : function()
42999 this.editorcore.pushValue();
43003 // hide stuff that is not compatible
43017 * @event specialkey
43021 * @cfg {String} fieldClass @hide
43024 * @cfg {String} focusClass @hide
43027 * @cfg {String} autoCreate @hide
43030 * @cfg {String} inputType @hide
43033 * @cfg {String} invalidClass @hide
43036 * @cfg {String} invalidText @hide
43039 * @cfg {String} msgFx @hide
43042 * @cfg {String} validateOnBlur @hide
43046 // <script type="text/javascript">
43049 * Ext JS Library 1.1.1
43050 * Copyright(c) 2006-2007, Ext JS, LLC.
43056 * @class Roo.form.HtmlEditorToolbar1
43061 new Roo.form.HtmlEditor({
43064 new Roo.form.HtmlEditorToolbar1({
43065 disable : { fonts: 1 , format: 1, ..., ... , ...],
43071 * @cfg {Object} disable List of elements to disable..
43072 * @cfg {Array} btns List of additional buttons.
43076 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
43079 Roo.form.HtmlEditor.ToolbarStandard = function(config)
43082 Roo.apply(this, config);
43084 // default disabled, based on 'good practice'..
43085 this.disable = this.disable || {};
43086 Roo.applyIf(this.disable, {
43089 specialElements : true
43093 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43094 // dont call parent... till later.
43097 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
43104 editorcore : false,
43106 * @cfg {Object} disable List of toolbar elements to disable
43113 * @cfg {String} createLinkText The default text for the create link prompt
43115 createLinkText : 'Please enter the URL for the link:',
43117 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
43119 defaultLinkValue : 'http:/'+'/',
43123 * @cfg {Array} fontFamilies An array of available font families
43141 // "á" , ?? a acute?
43146 "°" // , // degrees
43148 // "é" , // e ecute
43149 // "ú" , // u ecute?
43152 specialElements : [
43154 text: "Insert Table",
43157 ihtml : '<table><tr><td>Cell</td></tr></table>'
43161 text: "Insert Image",
43164 ihtml : '<img src="about:blank"/>'
43173 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43174 "input:submit", "input:button", "select", "textarea", "label" ],
43177 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43179 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43187 * @cfg {String} defaultFont default font to use.
43189 defaultFont: 'tahoma',
43191 fontSelect : false,
43194 formatCombo : false,
43196 init : function(editor)
43198 this.editor = editor;
43199 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43200 var editorcore = this.editorcore;
43204 var fid = editorcore.frameId;
43206 function btn(id, toggle, handler){
43207 var xid = fid + '-'+ id ;
43211 cls : 'x-btn-icon x-edit-'+id,
43212 enableToggle:toggle !== false,
43213 scope: _t, // was editor...
43214 handler:handler||_t.relayBtnCmd,
43215 clickEvent:'mousedown',
43216 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43223 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43225 // stop form submits
43226 tb.el.on('click', function(e){
43227 e.preventDefault(); // what does this do?
43230 if(!this.disable.font) { // && !Roo.isSafari){
43231 /* why no safari for fonts
43232 editor.fontSelect = tb.el.createChild({
43235 cls:'x-font-select',
43236 html: this.createFontOptions()
43239 editor.fontSelect.on('change', function(){
43240 var font = editor.fontSelect.dom.value;
43241 editor.relayCmd('fontname', font);
43242 editor.deferFocus();
43246 editor.fontSelect.dom,
43252 if(!this.disable.formats){
43253 this.formatCombo = new Roo.form.ComboBox({
43254 store: new Roo.data.SimpleStore({
43257 data : this.formats // from states.js
43261 //autoCreate : {tag: "div", size: "20"},
43262 displayField:'tag',
43266 triggerAction: 'all',
43267 emptyText:'Add tag',
43268 selectOnFocus:true,
43271 'select': function(c, r, i) {
43272 editorcore.insertTag(r.get('tag'));
43278 tb.addField(this.formatCombo);
43282 if(!this.disable.format){
43289 if(!this.disable.fontSize){
43294 btn('increasefontsize', false, editorcore.adjustFont),
43295 btn('decreasefontsize', false, editorcore.adjustFont)
43300 if(!this.disable.colors){
43303 id:editorcore.frameId +'-forecolor',
43304 cls:'x-btn-icon x-edit-forecolor',
43305 clickEvent:'mousedown',
43306 tooltip: this.buttonTips['forecolor'] || undefined,
43308 menu : new Roo.menu.ColorMenu({
43309 allowReselect: true,
43310 focus: Roo.emptyFn,
43313 selectHandler: function(cp, color){
43314 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43315 editor.deferFocus();
43318 clickEvent:'mousedown'
43321 id:editorcore.frameId +'backcolor',
43322 cls:'x-btn-icon x-edit-backcolor',
43323 clickEvent:'mousedown',
43324 tooltip: this.buttonTips['backcolor'] || undefined,
43326 menu : new Roo.menu.ColorMenu({
43327 focus: Roo.emptyFn,
43330 allowReselect: true,
43331 selectHandler: function(cp, color){
43333 editorcore.execCmd('useCSS', false);
43334 editorcore.execCmd('hilitecolor', color);
43335 editorcore.execCmd('useCSS', true);
43336 editor.deferFocus();
43338 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43339 Roo.isSafari || Roo.isIE ? '#'+color : color);
43340 editor.deferFocus();
43344 clickEvent:'mousedown'
43349 // now add all the items...
43352 if(!this.disable.alignments){
43355 btn('justifyleft'),
43356 btn('justifycenter'),
43357 btn('justifyright')
43361 //if(!Roo.isSafari){
43362 if(!this.disable.links){
43365 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43369 if(!this.disable.lists){
43372 btn('insertorderedlist'),
43373 btn('insertunorderedlist')
43376 if(!this.disable.sourceEdit){
43379 btn('sourceedit', true, function(btn){
43381 this.toggleSourceEdit(btn.pressed);
43388 // special menu.. - needs to be tidied up..
43389 if (!this.disable.special) {
43392 cls: 'x-edit-none',
43398 for (var i =0; i < this.specialChars.length; i++) {
43399 smenu.menu.items.push({
43401 html: this.specialChars[i],
43402 handler: function(a,b) {
43403 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43404 //editor.insertAtCursor(a.html);
43418 if (!this.disable.cleanStyles) {
43420 cls: 'x-btn-icon x-btn-clear',
43426 for (var i =0; i < this.cleanStyles.length; i++) {
43427 cmenu.menu.items.push({
43428 actiontype : this.cleanStyles[i],
43429 html: 'Remove ' + this.cleanStyles[i],
43430 handler: function(a,b) {
43433 var c = Roo.get(editorcore.doc.body);
43434 c.select('[style]').each(function(s) {
43435 s.dom.style.removeProperty(a.actiontype);
43437 editorcore.syncValue();
43442 cmenu.menu.items.push({
43443 actiontype : 'word',
43444 html: 'Remove MS Word Formating',
43445 handler: function(a,b) {
43446 editorcore.cleanWord();
43447 editorcore.syncValue();
43452 cmenu.menu.items.push({
43453 actiontype : 'all',
43454 html: 'Remove All Styles',
43455 handler: function(a,b) {
43457 var c = Roo.get(editorcore.doc.body);
43458 c.select('[style]').each(function(s) {
43459 s.dom.removeAttribute('style');
43461 editorcore.syncValue();
43465 cmenu.menu.items.push({
43466 actiontype : 'word',
43467 html: 'Tidy HTML Source',
43468 handler: function(a,b) {
43469 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43470 editorcore.syncValue();
43479 if (!this.disable.specialElements) {
43482 cls: 'x-edit-none',
43487 for (var i =0; i < this.specialElements.length; i++) {
43488 semenu.menu.items.push(
43490 handler: function(a,b) {
43491 editor.insertAtCursor(this.ihtml);
43493 }, this.specialElements[i])
43505 for(var i =0; i< this.btns.length;i++) {
43506 var b = Roo.factory(this.btns[i],Roo.form);
43507 b.cls = 'x-edit-none';
43508 b.scope = editorcore;
43516 // disable everything...
43518 this.tb.items.each(function(item){
43519 if(item.id != editorcore.frameId+ '-sourceedit'){
43523 this.rendered = true;
43525 // the all the btns;
43526 editor.on('editorevent', this.updateToolbar, this);
43527 // other toolbars need to implement this..
43528 //editor.on('editmodechange', this.updateToolbar, this);
43532 relayBtnCmd : function(btn) {
43533 this.editorcore.relayCmd(btn.cmd);
43535 // private used internally
43536 createLink : function(){
43537 Roo.log("create link?");
43538 var url = prompt(this.createLinkText, this.defaultLinkValue);
43539 if(url && url != 'http:/'+'/'){
43540 this.editorcore.relayCmd('createlink', url);
43546 * Protected method that will not generally be called directly. It triggers
43547 * a toolbar update by reading the markup state of the current selection in the editor.
43549 updateToolbar: function(){
43551 if(!this.editorcore.activated){
43552 this.editor.onFirstFocus();
43556 var btns = this.tb.items.map,
43557 doc = this.editorcore.doc,
43558 frameId = this.editorcore.frameId;
43560 if(!this.disable.font && !Roo.isSafari){
43562 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43563 if(name != this.fontSelect.dom.value){
43564 this.fontSelect.dom.value = name;
43568 if(!this.disable.format){
43569 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43570 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43571 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43573 if(!this.disable.alignments){
43574 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43575 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43576 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43578 if(!Roo.isSafari && !this.disable.lists){
43579 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43580 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43583 var ans = this.editorcore.getAllAncestors();
43584 if (this.formatCombo) {
43587 var store = this.formatCombo.store;
43588 this.formatCombo.setValue("");
43589 for (var i =0; i < ans.length;i++) {
43590 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43592 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43600 // hides menus... - so this cant be on a menu...
43601 Roo.menu.MenuMgr.hideAll();
43603 //this.editorsyncValue();
43607 createFontOptions : function(){
43608 var buf = [], fs = this.fontFamilies, ff, lc;
43612 for(var i = 0, len = fs.length; i< len; i++){
43614 lc = ff.toLowerCase();
43616 '<option value="',lc,'" style="font-family:',ff,';"',
43617 (this.defaultFont == lc ? ' selected="true">' : '>'),
43622 return buf.join('');
43625 toggleSourceEdit : function(sourceEditMode){
43627 Roo.log("toolbar toogle");
43628 if(sourceEditMode === undefined){
43629 sourceEditMode = !this.sourceEditMode;
43631 this.sourceEditMode = sourceEditMode === true;
43632 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43633 // just toggle the button?
43634 if(btn.pressed !== this.sourceEditMode){
43635 btn.toggle(this.sourceEditMode);
43639 if(sourceEditMode){
43640 Roo.log("disabling buttons");
43641 this.tb.items.each(function(item){
43642 if(item.cmd != 'sourceedit'){
43648 Roo.log("enabling buttons");
43649 if(this.editorcore.initialized){
43650 this.tb.items.each(function(item){
43656 Roo.log("calling toggole on editor");
43657 // tell the editor that it's been pressed..
43658 this.editor.toggleSourceEdit(sourceEditMode);
43662 * Object collection of toolbar tooltips for the buttons in the editor. The key
43663 * is the command id associated with that button and the value is a valid QuickTips object.
43668 title: 'Bold (Ctrl+B)',
43669 text: 'Make the selected text bold.',
43670 cls: 'x-html-editor-tip'
43673 title: 'Italic (Ctrl+I)',
43674 text: 'Make the selected text italic.',
43675 cls: 'x-html-editor-tip'
43683 title: 'Bold (Ctrl+B)',
43684 text: 'Make the selected text bold.',
43685 cls: 'x-html-editor-tip'
43688 title: 'Italic (Ctrl+I)',
43689 text: 'Make the selected text italic.',
43690 cls: 'x-html-editor-tip'
43693 title: 'Underline (Ctrl+U)',
43694 text: 'Underline the selected text.',
43695 cls: 'x-html-editor-tip'
43697 increasefontsize : {
43698 title: 'Grow Text',
43699 text: 'Increase the font size.',
43700 cls: 'x-html-editor-tip'
43702 decreasefontsize : {
43703 title: 'Shrink Text',
43704 text: 'Decrease the font size.',
43705 cls: 'x-html-editor-tip'
43708 title: 'Text Highlight Color',
43709 text: 'Change the background color of the selected text.',
43710 cls: 'x-html-editor-tip'
43713 title: 'Font Color',
43714 text: 'Change the color of the selected text.',
43715 cls: 'x-html-editor-tip'
43718 title: 'Align Text Left',
43719 text: 'Align text to the left.',
43720 cls: 'x-html-editor-tip'
43723 title: 'Center Text',
43724 text: 'Center text in the editor.',
43725 cls: 'x-html-editor-tip'
43728 title: 'Align Text Right',
43729 text: 'Align text to the right.',
43730 cls: 'x-html-editor-tip'
43732 insertunorderedlist : {
43733 title: 'Bullet List',
43734 text: 'Start a bulleted list.',
43735 cls: 'x-html-editor-tip'
43737 insertorderedlist : {
43738 title: 'Numbered List',
43739 text: 'Start a numbered list.',
43740 cls: 'x-html-editor-tip'
43743 title: 'Hyperlink',
43744 text: 'Make the selected text a hyperlink.',
43745 cls: 'x-html-editor-tip'
43748 title: 'Source Edit',
43749 text: 'Switch to source editing mode.',
43750 cls: 'x-html-editor-tip'
43754 onDestroy : function(){
43757 this.tb.items.each(function(item){
43759 item.menu.removeAll();
43761 item.menu.el.destroy();
43769 onFirstFocus: function() {
43770 this.tb.items.each(function(item){
43779 // <script type="text/javascript">
43782 * Ext JS Library 1.1.1
43783 * Copyright(c) 2006-2007, Ext JS, LLC.
43790 * @class Roo.form.HtmlEditor.ToolbarContext
43795 new Roo.form.HtmlEditor({
43798 { xtype: 'ToolbarStandard', styles : {} }
43799 { xtype: 'ToolbarContext', disable : {} }
43805 * @config : {Object} disable List of elements to disable.. (not done yet.)
43806 * @config : {Object} styles Map of styles available.
43810 Roo.form.HtmlEditor.ToolbarContext = function(config)
43813 Roo.apply(this, config);
43814 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43815 // dont call parent... till later.
43816 this.styles = this.styles || {};
43821 Roo.form.HtmlEditor.ToolbarContext.types = {
43833 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
43899 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
43904 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
43914 style : 'fontFamily',
43915 displayField: 'display',
43916 optname : 'font-family',
43965 // should we really allow this??
43966 // should this just be
43977 style : 'fontFamily',
43978 displayField: 'display',
43979 optname : 'font-family',
43986 style : 'fontFamily',
43987 displayField: 'display',
43988 optname : 'font-family',
43995 style : 'fontFamily',
43996 displayField: 'display',
43997 optname : 'font-family',
44008 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
44009 Roo.form.HtmlEditor.ToolbarContext.stores = false;
44011 Roo.form.HtmlEditor.ToolbarContext.options = {
44013 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
44014 [ 'Courier New', 'Courier New'],
44015 [ 'Tahoma', 'Tahoma'],
44016 [ 'Times New Roman,serif', 'Times'],
44017 [ 'Verdana','Verdana' ]
44021 // fixme - these need to be configurable..
44024 Roo.form.HtmlEditor.ToolbarContext.types
44027 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
44034 editorcore : false,
44036 * @cfg {Object} disable List of toolbar elements to disable
44041 * @cfg {Object} styles List of styles
44042 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
44044 * These must be defined in the page, so they get rendered correctly..
44055 init : function(editor)
44057 this.editor = editor;
44058 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44059 var editorcore = this.editorcore;
44061 var fid = editorcore.frameId;
44063 function btn(id, toggle, handler){
44064 var xid = fid + '-'+ id ;
44068 cls : 'x-btn-icon x-edit-'+id,
44069 enableToggle:toggle !== false,
44070 scope: editorcore, // was editor...
44071 handler:handler||editorcore.relayBtnCmd,
44072 clickEvent:'mousedown',
44073 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44077 // create a new element.
44078 var wdiv = editor.wrap.createChild({
44080 }, editor.wrap.dom.firstChild.nextSibling, true);
44082 // can we do this more than once??
44084 // stop form submits
44087 // disable everything...
44088 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44089 this.toolbars = {};
44091 for (var i in ty) {
44093 this.toolbars[i] = this.buildToolbar(ty[i],i);
44095 this.tb = this.toolbars.BODY;
44097 this.buildFooter();
44098 this.footer.show();
44099 editor.on('hide', function( ) { this.footer.hide() }, this);
44100 editor.on('show', function( ) { this.footer.show() }, this);
44103 this.rendered = true;
44105 // the all the btns;
44106 editor.on('editorevent', this.updateToolbar, this);
44107 // other toolbars need to implement this..
44108 //editor.on('editmodechange', this.updateToolbar, this);
44114 * Protected method that will not generally be called directly. It triggers
44115 * a toolbar update by reading the markup state of the current selection in the editor.
44117 updateToolbar: function(editor,ev,sel){
44120 // capture mouse up - this is handy for selecting images..
44121 // perhaps should go somewhere else...
44122 if(!this.editorcore.activated){
44123 this.editor.onFirstFocus();
44127 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
44128 // selectNode - might want to handle IE?
44130 (ev.type == 'mouseup' || ev.type == 'click' ) &&
44131 ev.target && ev.target.tagName == 'IMG') {
44132 // they have click on an image...
44133 // let's see if we can change the selection...
44136 var nodeRange = sel.ownerDocument.createRange();
44138 nodeRange.selectNode(sel);
44140 nodeRange.selectNodeContents(sel);
44142 //nodeRange.collapse(true);
44143 var s = this.editorcore.win.getSelection();
44144 s.removeAllRanges();
44145 s.addRange(nodeRange);
44149 var updateFooter = sel ? false : true;
44152 var ans = this.editorcore.getAllAncestors();
44155 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44158 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
44159 sel = sel ? sel : this.editorcore.doc.body;
44160 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44163 // pick a menu that exists..
44164 var tn = sel.tagName.toUpperCase();
44165 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44167 tn = sel.tagName.toUpperCase();
44169 var lastSel = this.tb.selectedNode
44171 this.tb.selectedNode = sel;
44173 // if current menu does not match..
44174 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
44177 ///console.log("show: " + tn);
44178 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44181 this.tb.items.first().el.innerHTML = tn + ': ';
44184 // update attributes
44185 if (this.tb.fields) {
44186 this.tb.fields.each(function(e) {
44188 e.setValue(sel.style[e.stylename]);
44191 e.setValue(sel.getAttribute(e.attrname));
44195 var hasStyles = false;
44196 for(var i in this.styles) {
44203 var st = this.tb.fields.item(0);
44205 st.store.removeAll();
44208 var cn = sel.className.split(/\s+/);
44211 if (this.styles['*']) {
44213 Roo.each(this.styles['*'], function(v) {
44214 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44217 if (this.styles[tn]) {
44218 Roo.each(this.styles[tn], function(v) {
44219 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44223 st.store.loadData(avs);
44227 // flag our selected Node.
44228 this.tb.selectedNode = sel;
44231 Roo.menu.MenuMgr.hideAll();
44235 if (!updateFooter) {
44236 //this.footDisp.dom.innerHTML = '';
44239 // update the footer
44243 this.footerEls = ans.reverse();
44244 Roo.each(this.footerEls, function(a,i) {
44245 if (!a) { return; }
44246 html += html.length ? ' > ' : '';
44248 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44253 var sz = this.footDisp.up('td').getSize();
44254 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44255 this.footDisp.dom.style.marginLeft = '5px';
44257 this.footDisp.dom.style.overflow = 'hidden';
44259 this.footDisp.dom.innerHTML = html;
44261 //this.editorsyncValue();
44268 onDestroy : function(){
44271 this.tb.items.each(function(item){
44273 item.menu.removeAll();
44275 item.menu.el.destroy();
44283 onFirstFocus: function() {
44284 // need to do this for all the toolbars..
44285 this.tb.items.each(function(item){
44289 buildToolbar: function(tlist, nm)
44291 var editor = this.editor;
44292 var editorcore = this.editorcore;
44293 // create a new element.
44294 var wdiv = editor.wrap.createChild({
44296 }, editor.wrap.dom.firstChild.nextSibling, true);
44299 var tb = new Roo.Toolbar(wdiv);
44302 tb.add(nm+ ": ");
44305 for(var i in this.styles) {
44310 if (styles && styles.length) {
44312 // this needs a multi-select checkbox...
44313 tb.addField( new Roo.form.ComboBox({
44314 store: new Roo.data.SimpleStore({
44316 fields: ['val', 'selected'],
44319 name : '-roo-edit-className',
44320 attrname : 'className',
44321 displayField: 'val',
44325 triggerAction: 'all',
44326 emptyText:'Select Style',
44327 selectOnFocus:true,
44330 'select': function(c, r, i) {
44331 // initial support only for on class per el..
44332 tb.selectedNode.className = r ? r.get('val') : '';
44333 editorcore.syncValue();
44340 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44341 var tbops = tbc.options;
44343 for (var i in tlist) {
44345 var item = tlist[i];
44346 tb.add(item.title + ": ");
44349 //optname == used so you can configure the options available..
44350 var opts = item.opts ? item.opts : false;
44351 if (item.optname) {
44352 opts = tbops[item.optname];
44357 // opts == pulldown..
44358 tb.addField( new Roo.form.ComboBox({
44359 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44361 fields: ['val', 'display'],
44364 name : '-roo-edit-' + i,
44366 stylename : item.style ? item.style : false,
44367 displayField: item.displayField ? item.displayField : 'val',
44368 valueField : 'val',
44370 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44372 triggerAction: 'all',
44373 emptyText:'Select',
44374 selectOnFocus:true,
44375 width: item.width ? item.width : 130,
44377 'select': function(c, r, i) {
44379 tb.selectedNode.style[c.stylename] = r.get('val');
44382 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44391 tb.addField( new Roo.form.TextField({
44394 //allowBlank:false,
44399 tb.addField( new Roo.form.TextField({
44400 name: '-roo-edit-' + i,
44407 'change' : function(f, nv, ov) {
44408 tb.selectedNode.setAttribute(f.attrname, nv);
44417 text: 'Remove Tag',
44420 click : function ()
44423 // undo does not work.
44425 var sn = tb.selectedNode;
44427 var pn = sn.parentNode;
44429 var stn = sn.childNodes[0];
44430 var en = sn.childNodes[sn.childNodes.length - 1 ];
44431 while (sn.childNodes.length) {
44432 var node = sn.childNodes[0];
44433 sn.removeChild(node);
44435 pn.insertBefore(node, sn);
44438 pn.removeChild(sn);
44439 var range = editorcore.createRange();
44441 range.setStart(stn,0);
44442 range.setEnd(en,0); //????
44443 //range.selectNode(sel);
44446 var selection = editorcore.getSelection();
44447 selection.removeAllRanges();
44448 selection.addRange(range);
44452 //_this.updateToolbar(null, null, pn);
44453 _this.updateToolbar(null, null, null);
44454 _this.footDisp.dom.innerHTML = '';
44464 tb.el.on('click', function(e){
44465 e.preventDefault(); // what does this do?
44467 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44470 // dont need to disable them... as they will get hidden
44475 buildFooter : function()
44478 var fel = this.editor.wrap.createChild();
44479 this.footer = new Roo.Toolbar(fel);
44480 // toolbar has scrolly on left / right?
44481 var footDisp= new Roo.Toolbar.Fill();
44487 handler : function() {
44488 _t.footDisp.scrollTo('left',0,true)
44492 this.footer.add( footDisp );
44497 handler : function() {
44499 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44503 var fel = Roo.get(footDisp.el);
44504 fel.addClass('x-editor-context');
44505 this.footDispWrap = fel;
44506 this.footDispWrap.overflow = 'hidden';
44508 this.footDisp = fel.createChild();
44509 this.footDispWrap.on('click', this.onContextClick, this)
44513 onContextClick : function (ev,dom)
44515 ev.preventDefault();
44516 var cn = dom.className;
44518 if (!cn.match(/x-ed-loc-/)) {
44521 var n = cn.split('-').pop();
44522 var ans = this.footerEls;
44526 var range = this.editorcore.createRange();
44528 range.selectNodeContents(sel);
44529 //range.selectNode(sel);
44532 var selection = this.editorcore.getSelection();
44533 selection.removeAllRanges();
44534 selection.addRange(range);
44538 this.updateToolbar(null, null, sel);
44555 * Ext JS Library 1.1.1
44556 * Copyright(c) 2006-2007, Ext JS, LLC.
44558 * Originally Released Under LGPL - original licence link has changed is not relivant.
44561 * <script type="text/javascript">
44565 * @class Roo.form.BasicForm
44566 * @extends Roo.util.Observable
44567 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44569 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44570 * @param {Object} config Configuration options
44572 Roo.form.BasicForm = function(el, config){
44573 this.allItems = [];
44574 this.childForms = [];
44575 Roo.apply(this, config);
44577 * The Roo.form.Field items in this form.
44578 * @type MixedCollection
44582 this.items = new Roo.util.MixedCollection(false, function(o){
44583 return o.id || (o.id = Roo.id());
44587 * @event beforeaction
44588 * Fires before any action is performed. Return false to cancel the action.
44589 * @param {Form} this
44590 * @param {Action} action The action to be performed
44592 beforeaction: true,
44594 * @event actionfailed
44595 * Fires when an action fails.
44596 * @param {Form} this
44597 * @param {Action} action The action that failed
44599 actionfailed : true,
44601 * @event actioncomplete
44602 * Fires when an action is completed.
44603 * @param {Form} this
44604 * @param {Action} action The action that completed
44606 actioncomplete : true
44611 Roo.form.BasicForm.superclass.constructor.call(this);
44614 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44616 * @cfg {String} method
44617 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
44620 * @cfg {DataReader} reader
44621 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
44622 * This is optional as there is built-in support for processing JSON.
44625 * @cfg {DataReader} errorReader
44626 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
44627 * This is completely optional as there is built-in support for processing JSON.
44630 * @cfg {String} url
44631 * The URL to use for form actions if one isn't supplied in the action options.
44634 * @cfg {Boolean} fileUpload
44635 * Set to true if this form is a file upload.
44639 * @cfg {Object} baseParams
44640 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
44645 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
44650 activeAction : null,
44653 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
44654 * or setValues() data instead of when the form was first created.
44656 trackResetOnLoad : false,
44660 * childForms - used for multi-tab forms
44663 childForms : false,
44666 * allItems - full list of fields.
44672 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
44673 * element by passing it or its id or mask the form itself by passing in true.
44676 waitMsgTarget : false,
44679 initEl : function(el){
44680 this.el = Roo.get(el);
44681 this.id = this.el.id || Roo.id();
44682 this.el.on('submit', this.onSubmit, this);
44683 this.el.addClass('x-form');
44687 onSubmit : function(e){
44692 * Returns true if client-side validation on the form is successful.
44695 isValid : function(){
44697 this.items.each(function(f){
44706 * Returns true if any fields in this form have changed since their original load.
44709 isDirty : function(){
44711 this.items.each(function(f){
44721 * Performs a predefined action (submit or load) or custom actions you define on this form.
44722 * @param {String} actionName The name of the action type
44723 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
44724 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
44725 * accept other config options):
44727 Property Type Description
44728 ---------------- --------------- ----------------------------------------------------------------------------------
44729 url String The url for the action (defaults to the form's url)
44730 method String The form method to use (defaults to the form's method, or POST if not defined)
44731 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
44732 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
44733 validate the form on the client (defaults to false)
44735 * @return {BasicForm} this
44737 doAction : function(action, options){
44738 if(typeof action == 'string'){
44739 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
44741 if(this.fireEvent('beforeaction', this, action) !== false){
44742 this.beforeAction(action);
44743 action.run.defer(100, action);
44749 * Shortcut to do a submit action.
44750 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44751 * @return {BasicForm} this
44753 submit : function(options){
44754 this.doAction('submit', options);
44759 * Shortcut to do a load action.
44760 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44761 * @return {BasicForm} this
44763 load : function(options){
44764 this.doAction('load', options);
44769 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
44770 * @param {Record} record The record to edit
44771 * @return {BasicForm} this
44773 updateRecord : function(record){
44774 record.beginEdit();
44775 var fs = record.fields;
44776 fs.each(function(f){
44777 var field = this.findField(f.name);
44779 record.set(f.name, field.getValue());
44787 * Loads an Roo.data.Record into this form.
44788 * @param {Record} record The record to load
44789 * @return {BasicForm} this
44791 loadRecord : function(record){
44792 this.setValues(record.data);
44797 beforeAction : function(action){
44798 var o = action.options;
44801 if(this.waitMsgTarget === true){
44802 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
44803 }else if(this.waitMsgTarget){
44804 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
44805 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
44807 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
44813 afterAction : function(action, success){
44814 this.activeAction = null;
44815 var o = action.options;
44817 if(this.waitMsgTarget === true){
44819 }else if(this.waitMsgTarget){
44820 this.waitMsgTarget.unmask();
44822 Roo.MessageBox.updateProgress(1);
44823 Roo.MessageBox.hide();
44830 Roo.callback(o.success, o.scope, [this, action]);
44831 this.fireEvent('actioncomplete', this, action);
44835 // failure condition..
44836 // we have a scenario where updates need confirming.
44837 // eg. if a locking scenario exists..
44838 // we look for { errors : { needs_confirm : true }} in the response.
44840 (typeof(action.result) != 'undefined') &&
44841 (typeof(action.result.errors) != 'undefined') &&
44842 (typeof(action.result.errors.needs_confirm) != 'undefined')
44845 Roo.MessageBox.confirm(
44846 "Change requires confirmation",
44847 action.result.errorMsg,
44852 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
44862 Roo.callback(o.failure, o.scope, [this, action]);
44863 // show an error message if no failed handler is set..
44864 if (!this.hasListener('actionfailed')) {
44865 Roo.MessageBox.alert("Error",
44866 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
44867 action.result.errorMsg :
44868 "Saving Failed, please check your entries or try again"
44872 this.fireEvent('actionfailed', this, action);
44878 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
44879 * @param {String} id The value to search for
44882 findField : function(id){
44883 var field = this.items.get(id);
44885 this.items.each(function(f){
44886 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
44892 return field || null;
44896 * Add a secondary form to this one,
44897 * Used to provide tabbed forms. One form is primary, with hidden values
44898 * which mirror the elements from the other forms.
44900 * @param {Roo.form.Form} form to add.
44903 addForm : function(form)
44906 if (this.childForms.indexOf(form) > -1) {
44910 this.childForms.push(form);
44912 Roo.each(form.allItems, function (fe) {
44914 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
44915 if (this.findField(n)) { // already added..
44918 var add = new Roo.form.Hidden({
44921 add.render(this.el);
44928 * Mark fields in this form invalid in bulk.
44929 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
44930 * @return {BasicForm} this
44932 markInvalid : function(errors){
44933 if(errors instanceof Array){
44934 for(var i = 0, len = errors.length; i < len; i++){
44935 var fieldError = errors[i];
44936 var f = this.findField(fieldError.id);
44938 f.markInvalid(fieldError.msg);
44944 if(typeof errors[id] != 'function' && (field = this.findField(id))){
44945 field.markInvalid(errors[id]);
44949 Roo.each(this.childForms || [], function (f) {
44950 f.markInvalid(errors);
44957 * Set values for fields in this form in bulk.
44958 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
44959 * @return {BasicForm} this
44961 setValues : function(values){
44962 if(values instanceof Array){ // array of objects
44963 for(var i = 0, len = values.length; i < len; i++){
44965 var f = this.findField(v.id);
44967 f.setValue(v.value);
44968 if(this.trackResetOnLoad){
44969 f.originalValue = f.getValue();
44973 }else{ // object hash
44976 if(typeof values[id] != 'function' && (field = this.findField(id))){
44978 if (field.setFromData &&
44979 field.valueField &&
44980 field.displayField &&
44981 // combos' with local stores can
44982 // be queried via setValue()
44983 // to set their value..
44984 (field.store && !field.store.isLocal)
44988 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44989 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44990 field.setFromData(sd);
44993 field.setValue(values[id]);
44997 if(this.trackResetOnLoad){
44998 field.originalValue = field.getValue();
45004 Roo.each(this.childForms || [], function (f) {
45005 f.setValues(values);
45012 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
45013 * they are returned as an array.
45014 * @param {Boolean} asString
45017 getValues : function(asString){
45018 if (this.childForms) {
45019 // copy values from the child forms
45020 Roo.each(this.childForms, function (f) {
45021 this.setValues(f.getValues());
45027 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
45028 if(asString === true){
45031 return Roo.urlDecode(fs);
45035 * Returns the fields in this form as an object with key/value pairs.
45036 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
45039 getFieldValues : function(with_hidden)
45041 if (this.childForms) {
45042 // copy values from the child forms
45043 // should this call getFieldValues - probably not as we do not currently copy
45044 // hidden fields when we generate..
45045 Roo.each(this.childForms, function (f) {
45046 this.setValues(f.getValues());
45051 this.items.each(function(f){
45052 if (!f.getName()) {
45055 var v = f.getValue();
45056 if (f.inputType =='radio') {
45057 if (typeof(ret[f.getName()]) == 'undefined') {
45058 ret[f.getName()] = ''; // empty..
45061 if (!f.el.dom.checked) {
45065 v = f.el.dom.value;
45069 // not sure if this supported any more..
45070 if ((typeof(v) == 'object') && f.getRawValue) {
45071 v = f.getRawValue() ; // dates..
45073 // combo boxes where name != hiddenName...
45074 if (f.name != f.getName()) {
45075 ret[f.name] = f.getRawValue();
45077 ret[f.getName()] = v;
45084 * Clears all invalid messages in this form.
45085 * @return {BasicForm} this
45087 clearInvalid : function(){
45088 this.items.each(function(f){
45092 Roo.each(this.childForms || [], function (f) {
45101 * Resets this form.
45102 * @return {BasicForm} this
45104 reset : function(){
45105 this.items.each(function(f){
45109 Roo.each(this.childForms || [], function (f) {
45118 * Add Roo.form components to this form.
45119 * @param {Field} field1
45120 * @param {Field} field2 (optional)
45121 * @param {Field} etc (optional)
45122 * @return {BasicForm} this
45125 this.items.addAll(Array.prototype.slice.call(arguments, 0));
45131 * Removes a field from the items collection (does NOT remove its markup).
45132 * @param {Field} field
45133 * @return {BasicForm} this
45135 remove : function(field){
45136 this.items.remove(field);
45141 * Looks at the fields in this form, checks them for an id attribute,
45142 * and calls applyTo on the existing dom element with that id.
45143 * @return {BasicForm} this
45145 render : function(){
45146 this.items.each(function(f){
45147 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
45155 * Calls {@link Ext#apply} for all fields in this form with the passed object.
45156 * @param {Object} values
45157 * @return {BasicForm} this
45159 applyToFields : function(o){
45160 this.items.each(function(f){
45167 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45168 * @param {Object} values
45169 * @return {BasicForm} this
45171 applyIfToFields : function(o){
45172 this.items.each(function(f){
45180 Roo.BasicForm = Roo.form.BasicForm;/*
45182 * Ext JS Library 1.1.1
45183 * Copyright(c) 2006-2007, Ext JS, LLC.
45185 * Originally Released Under LGPL - original licence link has changed is not relivant.
45188 * <script type="text/javascript">
45192 * @class Roo.form.Form
45193 * @extends Roo.form.BasicForm
45194 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45196 * @param {Object} config Configuration options
45198 Roo.form.Form = function(config){
45200 if (config.items) {
45201 xitems = config.items;
45202 delete config.items;
45206 Roo.form.Form.superclass.constructor.call(this, null, config);
45207 this.url = this.url || this.action;
45209 this.root = new Roo.form.Layout(Roo.applyIf({
45213 this.active = this.root;
45215 * Array of all the buttons that have been added to this form via {@link addButton}
45219 this.allItems = [];
45222 * @event clientvalidation
45223 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45224 * @param {Form} this
45225 * @param {Boolean} valid true if the form has passed client-side validation
45227 clientvalidation: true,
45230 * Fires when the form is rendered
45231 * @param {Roo.form.Form} form
45236 if (this.progressUrl) {
45237 // push a hidden field onto the list of fields..
45241 name : 'UPLOAD_IDENTIFIER'
45246 Roo.each(xitems, this.addxtype, this);
45252 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45254 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45257 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45260 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45262 buttonAlign:'center',
45265 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45270 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45271 * This property cascades to child containers if not set.
45276 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45277 * fires a looping event with that state. This is required to bind buttons to the valid
45278 * state using the config value formBind:true on the button.
45280 monitorValid : false,
45283 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45288 * @cfg {String} progressUrl - Url to return progress data
45291 progressUrl : false,
45294 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45295 * fields are added and the column is closed. If no fields are passed the column remains open
45296 * until end() is called.
45297 * @param {Object} config The config to pass to the column
45298 * @param {Field} field1 (optional)
45299 * @param {Field} field2 (optional)
45300 * @param {Field} etc (optional)
45301 * @return Column The column container object
45303 column : function(c){
45304 var col = new Roo.form.Column(c);
45306 if(arguments.length > 1){ // duplicate code required because of Opera
45307 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45314 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45315 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45316 * until end() is called.
45317 * @param {Object} config The config to pass to the fieldset
45318 * @param {Field} field1 (optional)
45319 * @param {Field} field2 (optional)
45320 * @param {Field} etc (optional)
45321 * @return FieldSet The fieldset container object
45323 fieldset : function(c){
45324 var fs = new Roo.form.FieldSet(c);
45326 if(arguments.length > 1){ // duplicate code required because of Opera
45327 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45334 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45335 * fields are added and the container is closed. If no fields are passed the container remains open
45336 * until end() is called.
45337 * @param {Object} config The config to pass to the Layout
45338 * @param {Field} field1 (optional)
45339 * @param {Field} field2 (optional)
45340 * @param {Field} etc (optional)
45341 * @return Layout The container object
45343 container : function(c){
45344 var l = new Roo.form.Layout(c);
45346 if(arguments.length > 1){ // duplicate code required because of Opera
45347 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45354 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45355 * @param {Object} container A Roo.form.Layout or subclass of Layout
45356 * @return {Form} this
45358 start : function(c){
45359 // cascade label info
45360 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45361 this.active.stack.push(c);
45362 c.ownerCt = this.active;
45368 * Closes the current open container
45369 * @return {Form} this
45372 if(this.active == this.root){
45375 this.active = this.active.ownerCt;
45380 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45381 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45382 * as the label of the field.
45383 * @param {Field} field1
45384 * @param {Field} field2 (optional)
45385 * @param {Field} etc. (optional)
45386 * @return {Form} this
45389 this.active.stack.push.apply(this.active.stack, arguments);
45390 this.allItems.push.apply(this.allItems,arguments);
45392 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45393 if(a[i].isFormField){
45398 Roo.form.Form.superclass.add.apply(this, r);
45408 * Find any element that has been added to a form, using it's ID or name
45409 * This can include framesets, columns etc. along with regular fields..
45410 * @param {String} id - id or name to find.
45412 * @return {Element} e - or false if nothing found.
45414 findbyId : function(id)
45420 Roo.each(this.allItems, function(f){
45421 if (f.id == id || f.name == id ){
45432 * Render this form into the passed container. This should only be called once!
45433 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45434 * @return {Form} this
45436 render : function(ct)
45442 var o = this.autoCreate || {
45444 method : this.method || 'POST',
45445 id : this.id || Roo.id()
45447 this.initEl(ct.createChild(o));
45449 this.root.render(this.el);
45453 this.items.each(function(f){
45454 f.render('x-form-el-'+f.id);
45457 if(this.buttons.length > 0){
45458 // tables are required to maintain order and for correct IE layout
45459 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45460 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45461 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45463 var tr = tb.getElementsByTagName('tr')[0];
45464 for(var i = 0, len = this.buttons.length; i < len; i++) {
45465 var b = this.buttons[i];
45466 var td = document.createElement('td');
45467 td.className = 'x-form-btn-td';
45468 b.render(tr.appendChild(td));
45471 if(this.monitorValid){ // initialize after render
45472 this.startMonitoring();
45474 this.fireEvent('rendered', this);
45479 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45480 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45481 * object or a valid Roo.DomHelper element config
45482 * @param {Function} handler The function called when the button is clicked
45483 * @param {Object} scope (optional) The scope of the handler function
45484 * @return {Roo.Button}
45486 addButton : function(config, handler, scope){
45490 minWidth: this.minButtonWidth,
45493 if(typeof config == "string"){
45496 Roo.apply(bc, config);
45498 var btn = new Roo.Button(null, bc);
45499 this.buttons.push(btn);
45504 * Adds a series of form elements (using the xtype property as the factory method.
45505 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45506 * @param {Object} config
45509 addxtype : function()
45511 var ar = Array.prototype.slice.call(arguments, 0);
45513 for(var i = 0; i < ar.length; i++) {
45515 continue; // skip -- if this happends something invalid got sent, we
45516 // should ignore it, as basically that interface element will not show up
45517 // and that should be pretty obvious!!
45520 if (Roo.form[ar[i].xtype]) {
45522 var fe = Roo.factory(ar[i], Roo.form);
45528 fe.store.form = this;
45533 this.allItems.push(fe);
45534 if (fe.items && fe.addxtype) {
45535 fe.addxtype.apply(fe, fe.items);
45545 // console.log('adding ' + ar[i].xtype);
45547 if (ar[i].xtype == 'Button') {
45548 //console.log('adding button');
45549 //console.log(ar[i]);
45550 this.addButton(ar[i]);
45551 this.allItems.push(fe);
45555 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45556 alert('end is not supported on xtype any more, use items');
45558 // //console.log('adding end');
45566 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45567 * option "monitorValid"
45569 startMonitoring : function(){
45572 Roo.TaskMgr.start({
45573 run : this.bindHandler,
45574 interval : this.monitorPoll || 200,
45581 * Stops monitoring of the valid state of this form
45583 stopMonitoring : function(){
45584 this.bound = false;
45588 bindHandler : function(){
45590 return false; // stops binding
45593 this.items.each(function(f){
45594 if(!f.isValid(true)){
45599 for(var i = 0, len = this.buttons.length; i < len; i++){
45600 var btn = this.buttons[i];
45601 if(btn.formBind === true && btn.disabled === valid){
45602 btn.setDisabled(!valid);
45605 this.fireEvent('clientvalidation', this, valid);
45619 Roo.Form = Roo.form.Form;
45622 * Ext JS Library 1.1.1
45623 * Copyright(c) 2006-2007, Ext JS, LLC.
45625 * Originally Released Under LGPL - original licence link has changed is not relivant.
45628 * <script type="text/javascript">
45631 // as we use this in bootstrap.
45632 Roo.namespace('Roo.form');
45634 * @class Roo.form.Action
45635 * Internal Class used to handle form actions
45637 * @param {Roo.form.BasicForm} el The form element or its id
45638 * @param {Object} config Configuration options
45643 // define the action interface
45644 Roo.form.Action = function(form, options){
45646 this.options = options || {};
45649 * Client Validation Failed
45652 Roo.form.Action.CLIENT_INVALID = 'client';
45654 * Server Validation Failed
45657 Roo.form.Action.SERVER_INVALID = 'server';
45659 * Connect to Server Failed
45662 Roo.form.Action.CONNECT_FAILURE = 'connect';
45664 * Reading Data from Server Failed
45667 Roo.form.Action.LOAD_FAILURE = 'load';
45669 Roo.form.Action.prototype = {
45671 failureType : undefined,
45672 response : undefined,
45673 result : undefined,
45675 // interface method
45676 run : function(options){
45680 // interface method
45681 success : function(response){
45685 // interface method
45686 handleResponse : function(response){
45690 // default connection failure
45691 failure : function(response){
45693 this.response = response;
45694 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45695 this.form.afterAction(this, false);
45698 processResponse : function(response){
45699 this.response = response;
45700 if(!response.responseText){
45703 this.result = this.handleResponse(response);
45704 return this.result;
45707 // utility functions used internally
45708 getUrl : function(appendParams){
45709 var url = this.options.url || this.form.url || this.form.el.dom.action;
45711 var p = this.getParams();
45713 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
45719 getMethod : function(){
45720 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
45723 getParams : function(){
45724 var bp = this.form.baseParams;
45725 var p = this.options.params;
45727 if(typeof p == "object"){
45728 p = Roo.urlEncode(Roo.applyIf(p, bp));
45729 }else if(typeof p == 'string' && bp){
45730 p += '&' + Roo.urlEncode(bp);
45733 p = Roo.urlEncode(bp);
45738 createCallback : function(){
45740 success: this.success,
45741 failure: this.failure,
45743 timeout: (this.form.timeout*1000),
45744 upload: this.form.fileUpload ? this.success : undefined
45749 Roo.form.Action.Submit = function(form, options){
45750 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
45753 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
45756 haveProgress : false,
45757 uploadComplete : false,
45759 // uploadProgress indicator.
45760 uploadProgress : function()
45762 if (!this.form.progressUrl) {
45766 if (!this.haveProgress) {
45767 Roo.MessageBox.progress("Uploading", "Uploading");
45769 if (this.uploadComplete) {
45770 Roo.MessageBox.hide();
45774 this.haveProgress = true;
45776 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
45778 var c = new Roo.data.Connection();
45780 url : this.form.progressUrl,
45785 success : function(req){
45786 //console.log(data);
45790 rdata = Roo.decode(req.responseText)
45792 Roo.log("Invalid data from server..");
45796 if (!rdata || !rdata.success) {
45798 Roo.MessageBox.alert(Roo.encode(rdata));
45801 var data = rdata.data;
45803 if (this.uploadComplete) {
45804 Roo.MessageBox.hide();
45809 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
45810 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
45813 this.uploadProgress.defer(2000,this);
45816 failure: function(data) {
45817 Roo.log('progress url failed ');
45828 // run get Values on the form, so it syncs any secondary forms.
45829 this.form.getValues();
45831 var o = this.options;
45832 var method = this.getMethod();
45833 var isPost = method == 'POST';
45834 if(o.clientValidation === false || this.form.isValid()){
45836 if (this.form.progressUrl) {
45837 this.form.findField('UPLOAD_IDENTIFIER').setValue(
45838 (new Date() * 1) + '' + Math.random());
45843 Roo.Ajax.request(Roo.apply(this.createCallback(), {
45844 form:this.form.el.dom,
45845 url:this.getUrl(!isPost),
45847 params:isPost ? this.getParams() : null,
45848 isUpload: this.form.fileUpload
45851 this.uploadProgress();
45853 }else if (o.clientValidation !== false){ // client validation failed
45854 this.failureType = Roo.form.Action.CLIENT_INVALID;
45855 this.form.afterAction(this, false);
45859 success : function(response)
45861 this.uploadComplete= true;
45862 if (this.haveProgress) {
45863 Roo.MessageBox.hide();
45867 var result = this.processResponse(response);
45868 if(result === true || result.success){
45869 this.form.afterAction(this, true);
45873 this.form.markInvalid(result.errors);
45874 this.failureType = Roo.form.Action.SERVER_INVALID;
45876 this.form.afterAction(this, false);
45878 failure : function(response)
45880 this.uploadComplete= true;
45881 if (this.haveProgress) {
45882 Roo.MessageBox.hide();
45885 this.response = response;
45886 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45887 this.form.afterAction(this, false);
45890 handleResponse : function(response){
45891 if(this.form.errorReader){
45892 var rs = this.form.errorReader.read(response);
45895 for(var i = 0, len = rs.records.length; i < len; i++) {
45896 var r = rs.records[i];
45897 errors[i] = r.data;
45900 if(errors.length < 1){
45904 success : rs.success,
45910 ret = Roo.decode(response.responseText);
45914 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
45924 Roo.form.Action.Load = function(form, options){
45925 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
45926 this.reader = this.form.reader;
45929 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
45934 Roo.Ajax.request(Roo.apply(
45935 this.createCallback(), {
45936 method:this.getMethod(),
45937 url:this.getUrl(false),
45938 params:this.getParams()
45942 success : function(response){
45944 var result = this.processResponse(response);
45945 if(result === true || !result.success || !result.data){
45946 this.failureType = Roo.form.Action.LOAD_FAILURE;
45947 this.form.afterAction(this, false);
45950 this.form.clearInvalid();
45951 this.form.setValues(result.data);
45952 this.form.afterAction(this, true);
45955 handleResponse : function(response){
45956 if(this.form.reader){
45957 var rs = this.form.reader.read(response);
45958 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
45960 success : rs.success,
45964 return Roo.decode(response.responseText);
45968 Roo.form.Action.ACTION_TYPES = {
45969 'load' : Roo.form.Action.Load,
45970 'submit' : Roo.form.Action.Submit
45973 * Ext JS Library 1.1.1
45974 * Copyright(c) 2006-2007, Ext JS, LLC.
45976 * Originally Released Under LGPL - original licence link has changed is not relivant.
45979 * <script type="text/javascript">
45983 * @class Roo.form.Layout
45984 * @extends Roo.Component
45985 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45987 * @param {Object} config Configuration options
45989 Roo.form.Layout = function(config){
45991 if (config.items) {
45992 xitems = config.items;
45993 delete config.items;
45995 Roo.form.Layout.superclass.constructor.call(this, config);
45997 Roo.each(xitems, this.addxtype, this);
46001 Roo.extend(Roo.form.Layout, Roo.Component, {
46003 * @cfg {String/Object} autoCreate
46004 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
46007 * @cfg {String/Object/Function} style
46008 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
46009 * a function which returns such a specification.
46012 * @cfg {String} labelAlign
46013 * Valid values are "left," "top" and "right" (defaults to "left")
46016 * @cfg {Number} labelWidth
46017 * Fixed width in pixels of all field labels (defaults to undefined)
46020 * @cfg {Boolean} clear
46021 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
46025 * @cfg {String} labelSeparator
46026 * The separator to use after field labels (defaults to ':')
46028 labelSeparator : ':',
46030 * @cfg {Boolean} hideLabels
46031 * True to suppress the display of field labels in this layout (defaults to false)
46033 hideLabels : false,
46036 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
46041 onRender : function(ct, position){
46042 if(this.el){ // from markup
46043 this.el = Roo.get(this.el);
46044 }else { // generate
46045 var cfg = this.getAutoCreate();
46046 this.el = ct.createChild(cfg, position);
46049 this.el.applyStyles(this.style);
46051 if(this.labelAlign){
46052 this.el.addClass('x-form-label-'+this.labelAlign);
46054 if(this.hideLabels){
46055 this.labelStyle = "display:none";
46056 this.elementStyle = "padding-left:0;";
46058 if(typeof this.labelWidth == 'number'){
46059 this.labelStyle = "width:"+this.labelWidth+"px;";
46060 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
46062 if(this.labelAlign == 'top'){
46063 this.labelStyle = "width:auto;";
46064 this.elementStyle = "padding-left:0;";
46067 var stack = this.stack;
46068 var slen = stack.length;
46070 if(!this.fieldTpl){
46071 var t = new Roo.Template(
46072 '<div class="x-form-item {5}">',
46073 '<label for="{0}" style="{2}">{1}{4}</label>',
46074 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46076 '</div><div class="x-form-clear-left"></div>'
46078 t.disableFormats = true;
46080 Roo.form.Layout.prototype.fieldTpl = t;
46082 for(var i = 0; i < slen; i++) {
46083 if(stack[i].isFormField){
46084 this.renderField(stack[i]);
46086 this.renderComponent(stack[i]);
46091 this.el.createChild({cls:'x-form-clear'});
46096 renderField : function(f){
46097 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
46100 f.labelStyle||this.labelStyle||'', //2
46101 this.elementStyle||'', //3
46102 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
46103 f.itemCls||this.itemCls||'' //5
46104 ], true).getPrevSibling());
46108 renderComponent : function(c){
46109 c.render(c.isLayout ? this.el : this.el.createChild());
46112 * Adds a object form elements (using the xtype property as the factory method.)
46113 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
46114 * @param {Object} config
46116 addxtype : function(o)
46118 // create the lement.
46119 o.form = this.form;
46120 var fe = Roo.factory(o, Roo.form);
46121 this.form.allItems.push(fe);
46122 this.stack.push(fe);
46124 if (fe.isFormField) {
46125 this.form.items.add(fe);
46133 * @class Roo.form.Column
46134 * @extends Roo.form.Layout
46135 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
46137 * @param {Object} config Configuration options
46139 Roo.form.Column = function(config){
46140 Roo.form.Column.superclass.constructor.call(this, config);
46143 Roo.extend(Roo.form.Column, Roo.form.Layout, {
46145 * @cfg {Number/String} width
46146 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46149 * @cfg {String/Object} autoCreate
46150 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
46154 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
46157 onRender : function(ct, position){
46158 Roo.form.Column.superclass.onRender.call(this, ct, position);
46160 this.el.setWidth(this.width);
46167 * @class Roo.form.Row
46168 * @extends Roo.form.Layout
46169 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46171 * @param {Object} config Configuration options
46175 Roo.form.Row = function(config){
46176 Roo.form.Row.superclass.constructor.call(this, config);
46179 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46181 * @cfg {Number/String} width
46182 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46185 * @cfg {Number/String} height
46186 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46188 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46192 onRender : function(ct, position){
46193 //console.log('row render');
46195 var t = new Roo.Template(
46196 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46197 '<label for="{0}" style="{2}">{1}{4}</label>',
46198 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46202 t.disableFormats = true;
46204 Roo.form.Layout.prototype.rowTpl = t;
46206 this.fieldTpl = this.rowTpl;
46208 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46209 var labelWidth = 100;
46211 if ((this.labelAlign != 'top')) {
46212 if (typeof this.labelWidth == 'number') {
46213 labelWidth = this.labelWidth
46215 this.padWidth = 20 + labelWidth;
46219 Roo.form.Column.superclass.onRender.call(this, ct, position);
46221 this.el.setWidth(this.width);
46224 this.el.setHeight(this.height);
46229 renderField : function(f){
46230 f.fieldEl = this.fieldTpl.append(this.el, [
46231 f.id, f.fieldLabel,
46232 f.labelStyle||this.labelStyle||'',
46233 this.elementStyle||'',
46234 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46235 f.itemCls||this.itemCls||'',
46236 f.width ? f.width + this.padWidth : 160 + this.padWidth
46243 * @class Roo.form.FieldSet
46244 * @extends Roo.form.Layout
46245 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46247 * @param {Object} config Configuration options
46249 Roo.form.FieldSet = function(config){
46250 Roo.form.FieldSet.superclass.constructor.call(this, config);
46253 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46255 * @cfg {String} legend
46256 * The text to display as the legend for the FieldSet (defaults to '')
46259 * @cfg {String/Object} autoCreate
46260 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46264 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46267 onRender : function(ct, position){
46268 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46270 this.setLegend(this.legend);
46275 setLegend : function(text){
46277 this.el.child('legend').update(text);
46282 * Ext JS Library 1.1.1
46283 * Copyright(c) 2006-2007, Ext JS, LLC.
46285 * Originally Released Under LGPL - original licence link has changed is not relivant.
46288 * <script type="text/javascript">
46291 * @class Roo.form.VTypes
46292 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46295 Roo.form.VTypes = function(){
46296 // closure these in so they are only created once.
46297 var alpha = /^[a-zA-Z_]+$/;
46298 var alphanum = /^[a-zA-Z0-9_]+$/;
46299 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46300 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46302 // All these messages and functions are configurable
46305 * The function used to validate email addresses
46306 * @param {String} value The email address
46308 'email' : function(v){
46309 return email.test(v);
46312 * The error text to display when the email validation function returns false
46315 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46317 * The keystroke filter mask to be applied on email input
46320 'emailMask' : /[a-z0-9_\.\-@]/i,
46323 * The function used to validate URLs
46324 * @param {String} value The URL
46326 'url' : function(v){
46327 return url.test(v);
46330 * The error text to display when the url validation function returns false
46333 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46336 * The function used to validate alpha values
46337 * @param {String} value The value
46339 'alpha' : function(v){
46340 return alpha.test(v);
46343 * The error text to display when the alpha validation function returns false
46346 'alphaText' : 'This field should only contain letters and _',
46348 * The keystroke filter mask to be applied on alpha input
46351 'alphaMask' : /[a-z_]/i,
46354 * The function used to validate alphanumeric values
46355 * @param {String} value The value
46357 'alphanum' : function(v){
46358 return alphanum.test(v);
46361 * The error text to display when the alphanumeric validation function returns false
46364 'alphanumText' : 'This field should only contain letters, numbers and _',
46366 * The keystroke filter mask to be applied on alphanumeric input
46369 'alphanumMask' : /[a-z0-9_]/i
46371 }();//<script type="text/javascript">
46374 * @class Roo.form.FCKeditor
46375 * @extends Roo.form.TextArea
46376 * Wrapper around the FCKEditor http://www.fckeditor.net
46378 * Creates a new FCKeditor
46379 * @param {Object} config Configuration options
46381 Roo.form.FCKeditor = function(config){
46382 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46385 * @event editorinit
46386 * Fired when the editor is initialized - you can add extra handlers here..
46387 * @param {FCKeditor} this
46388 * @param {Object} the FCK object.
46395 Roo.form.FCKeditor.editors = { };
46396 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46398 //defaultAutoCreate : {
46399 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46403 * @cfg {Object} fck options - see fck manual for details.
46408 * @cfg {Object} fck toolbar set (Basic or Default)
46410 toolbarSet : 'Basic',
46412 * @cfg {Object} fck BasePath
46414 basePath : '/fckeditor/',
46422 onRender : function(ct, position)
46425 this.defaultAutoCreate = {
46427 style:"width:300px;height:60px;",
46428 autocomplete: "off"
46431 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46434 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46435 if(this.preventScrollbars){
46436 this.el.setStyle("overflow", "hidden");
46438 this.el.setHeight(this.growMin);
46441 //console.log('onrender' + this.getId() );
46442 Roo.form.FCKeditor.editors[this.getId()] = this;
46445 this.replaceTextarea() ;
46449 getEditor : function() {
46450 return this.fckEditor;
46453 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46454 * @param {Mixed} value The value to set
46458 setValue : function(value)
46460 //console.log('setValue: ' + value);
46462 if(typeof(value) == 'undefined') { // not sure why this is happending...
46465 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46467 //if(!this.el || !this.getEditor()) {
46468 // this.value = value;
46469 //this.setValue.defer(100,this,[value]);
46473 if(!this.getEditor()) {
46477 this.getEditor().SetData(value);
46484 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46485 * @return {Mixed} value The field value
46487 getValue : function()
46490 if (this.frame && this.frame.dom.style.display == 'none') {
46491 return Roo.form.FCKeditor.superclass.getValue.call(this);
46494 if(!this.el || !this.getEditor()) {
46496 // this.getValue.defer(100,this);
46501 var value=this.getEditor().GetData();
46502 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46503 return Roo.form.FCKeditor.superclass.getValue.call(this);
46509 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46510 * @return {Mixed} value The field value
46512 getRawValue : function()
46514 if (this.frame && this.frame.dom.style.display == 'none') {
46515 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46518 if(!this.el || !this.getEditor()) {
46519 //this.getRawValue.defer(100,this);
46526 var value=this.getEditor().GetData();
46527 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46528 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46532 setSize : function(w,h) {
46536 //if (this.frame && this.frame.dom.style.display == 'none') {
46537 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46540 //if(!this.el || !this.getEditor()) {
46541 // this.setSize.defer(100,this, [w,h]);
46547 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46549 this.frame.dom.setAttribute('width', w);
46550 this.frame.dom.setAttribute('height', h);
46551 this.frame.setSize(w,h);
46555 toggleSourceEdit : function(value) {
46559 this.el.dom.style.display = value ? '' : 'none';
46560 this.frame.dom.style.display = value ? 'none' : '';
46565 focus: function(tag)
46567 if (this.frame.dom.style.display == 'none') {
46568 return Roo.form.FCKeditor.superclass.focus.call(this);
46570 if(!this.el || !this.getEditor()) {
46571 this.focus.defer(100,this, [tag]);
46578 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46579 this.getEditor().Focus();
46581 if (!this.getEditor().Selection.GetSelection()) {
46582 this.focus.defer(100,this, [tag]);
46587 var r = this.getEditor().EditorDocument.createRange();
46588 r.setStart(tgs[0],0);
46589 r.setEnd(tgs[0],0);
46590 this.getEditor().Selection.GetSelection().removeAllRanges();
46591 this.getEditor().Selection.GetSelection().addRange(r);
46592 this.getEditor().Focus();
46599 replaceTextarea : function()
46601 if ( document.getElementById( this.getId() + '___Frame' ) )
46603 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46605 // We must check the elements firstly using the Id and then the name.
46606 var oTextarea = document.getElementById( this.getId() );
46608 var colElementsByName = document.getElementsByName( this.getId() ) ;
46610 oTextarea.style.display = 'none' ;
46612 if ( oTextarea.tabIndex ) {
46613 this.TabIndex = oTextarea.tabIndex ;
46616 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46617 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46618 this.frame = Roo.get(this.getId() + '___Frame')
46621 _getConfigHtml : function()
46625 for ( var o in this.fckconfig ) {
46626 sConfig += sConfig.length > 0 ? '&' : '';
46627 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
46630 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
46634 _getIFrameHtml : function()
46636 var sFile = 'fckeditor.html' ;
46637 /* no idea what this is about..
46640 if ( (/fcksource=true/i).test( window.top.location.search ) )
46641 sFile = 'fckeditor.original.html' ;
46646 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
46647 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
46650 var html = '<iframe id="' + this.getId() +
46651 '___Frame" src="' + sLink +
46652 '" width="' + this.width +
46653 '" height="' + this.height + '"' +
46654 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
46655 ' frameborder="0" scrolling="no"></iframe>' ;
46660 _insertHtmlBefore : function( html, element )
46662 if ( element.insertAdjacentHTML ) {
46664 element.insertAdjacentHTML( 'beforeBegin', html ) ;
46666 var oRange = document.createRange() ;
46667 oRange.setStartBefore( element ) ;
46668 var oFragment = oRange.createContextualFragment( html );
46669 element.parentNode.insertBefore( oFragment, element ) ;
46682 //Roo.reg('fckeditor', Roo.form.FCKeditor);
46684 function FCKeditor_OnComplete(editorInstance){
46685 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
46686 f.fckEditor = editorInstance;
46687 //console.log("loaded");
46688 f.fireEvent('editorinit', f, editorInstance);
46708 //<script type="text/javascript">
46710 * @class Roo.form.GridField
46711 * @extends Roo.form.Field
46712 * Embed a grid (or editable grid into a form)
46715 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
46717 * xgrid.store = Roo.data.Store
46718 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
46719 * xgrid.store.reader = Roo.data.JsonReader
46723 * Creates a new GridField
46724 * @param {Object} config Configuration options
46726 Roo.form.GridField = function(config){
46727 Roo.form.GridField.superclass.constructor.call(this, config);
46731 Roo.extend(Roo.form.GridField, Roo.form.Field, {
46733 * @cfg {Number} width - used to restrict width of grid..
46737 * @cfg {Number} height - used to restrict height of grid..
46741 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
46747 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46748 * {tag: "input", type: "checkbox", autocomplete: "off"})
46750 // defaultAutoCreate : { tag: 'div' },
46751 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46753 * @cfg {String} addTitle Text to include for adding a title.
46757 onResize : function(){
46758 Roo.form.Field.superclass.onResize.apply(this, arguments);
46761 initEvents : function(){
46762 // Roo.form.Checkbox.superclass.initEvents.call(this);
46763 // has no events...
46768 getResizeEl : function(){
46772 getPositionEl : function(){
46777 onRender : function(ct, position){
46779 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
46780 var style = this.style;
46783 Roo.form.GridField.superclass.onRender.call(this, ct, position);
46784 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
46785 this.viewEl = this.wrap.createChild({ tag: 'div' });
46787 this.viewEl.applyStyles(style);
46790 this.viewEl.setWidth(this.width);
46793 this.viewEl.setHeight(this.height);
46795 //if(this.inputValue !== undefined){
46796 //this.setValue(this.value);
46799 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
46802 this.grid.render();
46803 this.grid.getDataSource().on('remove', this.refreshValue, this);
46804 this.grid.getDataSource().on('update', this.refreshValue, this);
46805 this.grid.on('afteredit', this.refreshValue, this);
46811 * Sets the value of the item.
46812 * @param {String} either an object or a string..
46814 setValue : function(v){
46816 v = v || []; // empty set..
46817 // this does not seem smart - it really only affects memoryproxy grids..
46818 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
46819 var ds = this.grid.getDataSource();
46820 // assumes a json reader..
46822 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
46823 ds.loadData( data);
46825 // clear selection so it does not get stale.
46826 if (this.grid.sm) {
46827 this.grid.sm.clearSelections();
46830 Roo.form.GridField.superclass.setValue.call(this, v);
46831 this.refreshValue();
46832 // should load data in the grid really....
46836 refreshValue: function() {
46838 this.grid.getDataSource().each(function(r) {
46841 this.el.dom.value = Roo.encode(val);
46849 * Ext JS Library 1.1.1
46850 * Copyright(c) 2006-2007, Ext JS, LLC.
46852 * Originally Released Under LGPL - original licence link has changed is not relivant.
46855 * <script type="text/javascript">
46858 * @class Roo.form.DisplayField
46859 * @extends Roo.form.Field
46860 * A generic Field to display non-editable data.
46862 * Creates a new Display Field item.
46863 * @param {Object} config Configuration options
46865 Roo.form.DisplayField = function(config){
46866 Roo.form.DisplayField.superclass.constructor.call(this, config);
46870 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
46871 inputType: 'hidden',
46877 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46879 focusClass : undefined,
46881 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46883 fieldClass: 'x-form-field',
46886 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
46888 valueRenderer: undefined,
46892 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46893 * {tag: "input", type: "checkbox", autocomplete: "off"})
46896 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46898 onResize : function(){
46899 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
46903 initEvents : function(){
46904 // Roo.form.Checkbox.superclass.initEvents.call(this);
46905 // has no events...
46910 getResizeEl : function(){
46914 getPositionEl : function(){
46919 onRender : function(ct, position){
46921 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
46922 //if(this.inputValue !== undefined){
46923 this.wrap = this.el.wrap();
46925 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
46927 if (this.bodyStyle) {
46928 this.viewEl.applyStyles(this.bodyStyle);
46930 //this.viewEl.setStyle('padding', '2px');
46932 this.setValue(this.value);
46937 initValue : Roo.emptyFn,
46942 onClick : function(){
46947 * Sets the checked state of the checkbox.
46948 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
46950 setValue : function(v){
46952 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
46953 // this might be called before we have a dom element..
46954 if (!this.viewEl) {
46957 this.viewEl.dom.innerHTML = html;
46958 Roo.form.DisplayField.superclass.setValue.call(this, v);
46968 * @class Roo.form.DayPicker
46969 * @extends Roo.form.Field
46970 * A Day picker show [M] [T] [W] ....
46972 * Creates a new Day Picker
46973 * @param {Object} config Configuration options
46975 Roo.form.DayPicker= function(config){
46976 Roo.form.DayPicker.superclass.constructor.call(this, config);
46980 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
46982 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46984 focusClass : undefined,
46986 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46988 fieldClass: "x-form-field",
46991 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46992 * {tag: "input", type: "checkbox", autocomplete: "off"})
46994 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
46997 actionMode : 'viewEl',
47001 inputType : 'hidden',
47004 inputElement: false, // real input element?
47005 basedOn: false, // ????
47007 isFormField: true, // not sure where this is needed!!!!
47009 onResize : function(){
47010 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
47011 if(!this.boxLabel){
47012 this.el.alignTo(this.wrap, 'c-c');
47016 initEvents : function(){
47017 Roo.form.Checkbox.superclass.initEvents.call(this);
47018 this.el.on("click", this.onClick, this);
47019 this.el.on("change", this.onClick, this);
47023 getResizeEl : function(){
47027 getPositionEl : function(){
47033 onRender : function(ct, position){
47034 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
47036 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
47038 var r1 = '<table><tr>';
47039 var r2 = '<tr class="x-form-daypick-icons">';
47040 for (var i=0; i < 7; i++) {
47041 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
47042 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
47045 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
47046 viewEl.select('img').on('click', this.onClick, this);
47047 this.viewEl = viewEl;
47050 // this will not work on Chrome!!!
47051 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
47052 this.el.on('propertychange', this.setFromHidden, this); //ie
47060 initValue : Roo.emptyFn,
47063 * Returns the checked state of the checkbox.
47064 * @return {Boolean} True if checked, else false
47066 getValue : function(){
47067 return this.el.dom.value;
47072 onClick : function(e){
47073 //this.setChecked(!this.checked);
47074 Roo.get(e.target).toggleClass('x-menu-item-checked');
47075 this.refreshValue();
47076 //if(this.el.dom.checked != this.checked){
47077 // this.setValue(this.el.dom.checked);
47082 refreshValue : function()
47085 this.viewEl.select('img',true).each(function(e,i,n) {
47086 val += e.is(".x-menu-item-checked") ? String(n) : '';
47088 this.setValue(val, true);
47092 * Sets the checked state of the checkbox.
47093 * On is always based on a string comparison between inputValue and the param.
47094 * @param {Boolean/String} value - the value to set
47095 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
47097 setValue : function(v,suppressEvent){
47098 if (!this.el.dom) {
47101 var old = this.el.dom.value ;
47102 this.el.dom.value = v;
47103 if (suppressEvent) {
47107 // update display..
47108 this.viewEl.select('img',true).each(function(e,i,n) {
47110 var on = e.is(".x-menu-item-checked");
47111 var newv = v.indexOf(String(n)) > -1;
47113 e.toggleClass('x-menu-item-checked');
47119 this.fireEvent('change', this, v, old);
47124 // handle setting of hidden value by some other method!!?!?
47125 setFromHidden: function()
47130 //console.log("SET FROM HIDDEN");
47131 //alert('setFrom hidden');
47132 this.setValue(this.el.dom.value);
47135 onDestroy : function()
47138 Roo.get(this.viewEl).remove();
47141 Roo.form.DayPicker.superclass.onDestroy.call(this);
47145 * RooJS Library 1.1.1
47146 * Copyright(c) 2008-2011 Alan Knowles
47153 * @class Roo.form.ComboCheck
47154 * @extends Roo.form.ComboBox
47155 * A combobox for multiple select items.
47157 * FIXME - could do with a reset button..
47160 * Create a new ComboCheck
47161 * @param {Object} config Configuration options
47163 Roo.form.ComboCheck = function(config){
47164 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47165 // should verify some data...
47167 // hiddenName = required..
47168 // displayField = required
47169 // valudField == required
47170 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47172 Roo.each(req, function(e) {
47173 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47174 throw "Roo.form.ComboCheck : missing value for: " + e;
47181 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47186 selectedClass: 'x-menu-item-checked',
47189 onRender : function(ct, position){
47195 var cls = 'x-combo-list';
47198 this.tpl = new Roo.Template({
47199 html : '<div class="'+cls+'-item x-menu-check-item">' +
47200 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47201 '<span>{' + this.displayField + '}</span>' +
47208 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47209 this.view.singleSelect = false;
47210 this.view.multiSelect = true;
47211 this.view.toggleSelect = true;
47212 this.pageTb.add(new Roo.Toolbar.Fill(), {
47215 handler: function()
47222 onViewOver : function(e, t){
47228 onViewClick : function(doFocus,index){
47232 select: function () {
47233 //Roo.log("SELECT CALLED");
47236 selectByValue : function(xv, scrollIntoView){
47237 var ar = this.getValueArray();
47240 Roo.each(ar, function(v) {
47241 if(v === undefined || v === null){
47244 var r = this.findRecord(this.valueField, v);
47246 sels.push(this.store.indexOf(r))
47250 this.view.select(sels);
47256 onSelect : function(record, index){
47257 // Roo.log("onselect Called");
47258 // this is only called by the clear button now..
47259 this.view.clearSelections();
47260 this.setValue('[]');
47261 if (this.value != this.valueBefore) {
47262 this.fireEvent('change', this, this.value, this.valueBefore);
47263 this.valueBefore = this.value;
47266 getValueArray : function()
47271 //Roo.log(this.value);
47272 if (typeof(this.value) == 'undefined') {
47275 var ar = Roo.decode(this.value);
47276 return ar instanceof Array ? ar : []; //?? valid?
47279 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47284 expand : function ()
47287 Roo.form.ComboCheck.superclass.expand.call(this);
47288 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47289 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47294 collapse : function(){
47295 Roo.form.ComboCheck.superclass.collapse.call(this);
47296 var sl = this.view.getSelectedIndexes();
47297 var st = this.store;
47301 Roo.each(sl, function(i) {
47303 nv.push(r.get(this.valueField));
47305 this.setValue(Roo.encode(nv));
47306 if (this.value != this.valueBefore) {
47308 this.fireEvent('change', this, this.value, this.valueBefore);
47309 this.valueBefore = this.value;
47314 setValue : function(v){
47318 var vals = this.getValueArray();
47320 Roo.each(vals, function(k) {
47321 var r = this.findRecord(this.valueField, k);
47323 tv.push(r.data[this.displayField]);
47324 }else if(this.valueNotFoundText !== undefined){
47325 tv.push( this.valueNotFoundText );
47330 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47331 this.hiddenField.value = v;
47337 * Ext JS Library 1.1.1
47338 * Copyright(c) 2006-2007, Ext JS, LLC.
47340 * Originally Released Under LGPL - original licence link has changed is not relivant.
47343 * <script type="text/javascript">
47347 * @class Roo.form.Signature
47348 * @extends Roo.form.Field
47352 * @param {Object} config Configuration options
47355 Roo.form.Signature = function(config){
47356 Roo.form.Signature.superclass.constructor.call(this, config);
47358 this.addEvents({// not in used??
47361 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47362 * @param {Roo.form.Signature} combo This combo box
47367 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47368 * @param {Roo.form.ComboBox} combo This combo box
47369 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47375 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47377 * @cfg {Object} labels Label to use when rendering a form.
47381 * confirm : "Confirm"
47386 confirm : "Confirm"
47389 * @cfg {Number} width The signature panel width (defaults to 300)
47393 * @cfg {Number} height The signature panel height (defaults to 100)
47397 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47399 allowBlank : false,
47402 // {Object} signPanel The signature SVG panel element (defaults to {})
47404 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47405 isMouseDown : false,
47406 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47407 isConfirmed : false,
47408 // {String} signatureTmp SVG mapping string (defaults to empty string)
47412 defaultAutoCreate : { // modified by initCompnoent..
47418 onRender : function(ct, position){
47420 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47422 this.wrap = this.el.wrap({
47423 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47426 this.createToolbar(this);
47427 this.signPanel = this.wrap.createChild({
47429 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47433 this.svgID = Roo.id();
47434 this.svgEl = this.signPanel.createChild({
47435 xmlns : 'http://www.w3.org/2000/svg',
47437 id : this.svgID + "-svg",
47439 height: this.height,
47440 viewBox: '0 0 '+this.width+' '+this.height,
47444 id: this.svgID + "-svg-r",
47446 height: this.height,
47451 id: this.svgID + "-svg-l",
47453 y1: (this.height*0.8), // start set the line in 80% of height
47454 x2: this.width, // end
47455 y2: (this.height*0.8), // end set the line in 80% of height
47457 'stroke-width': "1",
47458 'stroke-dasharray': "3",
47459 'shape-rendering': "crispEdges",
47460 'pointer-events': "none"
47464 id: this.svgID + "-svg-p",
47466 'stroke-width': "3",
47468 'pointer-events': 'none'
47473 this.svgBox = this.svgEl.dom.getScreenCTM();
47475 createSVG : function(){
47476 var svg = this.signPanel;
47477 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47480 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47481 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47482 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47483 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47484 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47485 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47486 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47489 isTouchEvent : function(e){
47490 return e.type.match(/^touch/);
47492 getCoords : function (e) {
47493 var pt = this.svgEl.dom.createSVGPoint();
47496 if (this.isTouchEvent(e)) {
47497 pt.x = e.targetTouches[0].clientX
47498 pt.y = e.targetTouches[0].clientY;
47500 var a = this.svgEl.dom.getScreenCTM();
47501 var b = a.inverse();
47502 var mx = pt.matrixTransform(b);
47503 return mx.x + ',' + mx.y;
47505 //mouse event headler
47506 down : function (e) {
47507 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47508 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47510 this.isMouseDown = true;
47512 e.preventDefault();
47514 move : function (e) {
47515 if (this.isMouseDown) {
47516 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47517 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47520 e.preventDefault();
47522 up : function (e) {
47523 this.isMouseDown = false;
47524 var sp = this.signatureTmp.split(' ');
47527 if(!sp[sp.length-2].match(/^L/)){
47531 this.signatureTmp = sp.join(" ");
47534 if(this.getValue() != this.signatureTmp){
47535 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47536 this.isConfirmed = false;
47538 e.preventDefault();
47542 * Protected method that will not generally be called directly. It
47543 * is called when the editor creates its toolbar. Override this method if you need to
47544 * add custom toolbar buttons.
47545 * @param {HtmlEditor} editor
47547 createToolbar : function(editor){
47548 function btn(id, toggle, handler){
47549 var xid = fid + '-'+ id ;
47553 cls : 'x-btn-icon x-edit-'+id,
47554 enableToggle:toggle !== false,
47555 scope: editor, // was editor...
47556 handler:handler||editor.relayBtnCmd,
47557 clickEvent:'mousedown',
47558 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47564 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47568 cls : ' x-signature-btn x-signature-'+id,
47569 scope: editor, // was editor...
47570 handler: this.reset,
47571 clickEvent:'mousedown',
47572 text: this.labels.clear
47579 cls : ' x-signature-btn x-signature-'+id,
47580 scope: editor, // was editor...
47581 handler: this.confirmHandler,
47582 clickEvent:'mousedown',
47583 text: this.labels.confirm
47590 * when user is clicked confirm then show this image.....
47592 * @return {String} Image Data URI
47594 getImageDataURI : function(){
47595 var svg = this.svgEl.dom.parentNode.innerHTML;
47596 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47601 * @return {Boolean} this.isConfirmed
47603 getConfirmed : function(){
47604 return this.isConfirmed;
47608 * @return {Number} this.width
47610 getWidth : function(){
47615 * @return {Number} this.height
47617 getHeight : function(){
47618 return this.height;
47621 getSignature : function(){
47622 return this.signatureTmp;
47625 reset : function(){
47626 this.signatureTmp = '';
47627 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47628 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
47629 this.isConfirmed = false;
47630 Roo.form.Signature.superclass.reset.call(this);
47632 setSignature : function(s){
47633 this.signatureTmp = s;
47634 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47635 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
47637 this.isConfirmed = false;
47638 Roo.form.Signature.superclass.reset.call(this);
47641 // Roo.log(this.signPanel.dom.contentWindow.up())
47644 setConfirmed : function(){
47648 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
47651 confirmHandler : function(){
47652 if(!this.getSignature()){
47656 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
47657 this.setValue(this.getSignature());
47658 this.isConfirmed = true;
47660 this.fireEvent('confirm', this);
47663 // Subclasses should provide the validation implementation by overriding this
47664 validateValue : function(value){
47665 if(this.allowBlank){
47669 if(this.isConfirmed){
47676 * Ext JS Library 1.1.1
47677 * Copyright(c) 2006-2007, Ext JS, LLC.
47679 * Originally Released Under LGPL - original licence link has changed is not relivant.
47682 * <script type="text/javascript">
47687 * @class Roo.form.ComboBox
47688 * @extends Roo.form.TriggerField
47689 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
47691 * Create a new ComboBox.
47692 * @param {Object} config Configuration options
47694 Roo.form.Select = function(config){
47695 Roo.form.Select.superclass.constructor.call(this, config);
47699 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
47701 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
47704 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
47705 * rendering into an Roo.Editor, defaults to false)
47708 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
47709 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
47712 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
47715 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
47716 * the dropdown list (defaults to undefined, with no header element)
47720 * @cfg {String/Roo.Template} tpl The template to use to render the output
47724 defaultAutoCreate : {tag: "select" },
47726 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
47728 listWidth: undefined,
47730 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
47731 * mode = 'remote' or 'text' if mode = 'local')
47733 displayField: undefined,
47735 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
47736 * mode = 'remote' or 'value' if mode = 'local').
47737 * Note: use of a valueField requires the user make a selection
47738 * in order for a value to be mapped.
47740 valueField: undefined,
47744 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
47745 * field's data value (defaults to the underlying DOM element's name)
47747 hiddenName: undefined,
47749 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
47753 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
47755 selectedClass: 'x-combo-selected',
47757 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
47758 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
47759 * which displays a downward arrow icon).
47761 triggerClass : 'x-form-arrow-trigger',
47763 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
47767 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
47768 * anchor positions (defaults to 'tl-bl')
47770 listAlign: 'tl-bl?',
47772 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
47776 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
47777 * query specified by the allQuery config option (defaults to 'query')
47779 triggerAction: 'query',
47781 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
47782 * (defaults to 4, does not apply if editable = false)
47786 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
47787 * delay (typeAheadDelay) if it matches a known value (defaults to false)
47791 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
47792 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
47796 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
47797 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
47801 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
47802 * when editable = true (defaults to false)
47804 selectOnFocus:false,
47806 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
47808 queryParam: 'query',
47810 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
47811 * when mode = 'remote' (defaults to 'Loading...')
47813 loadingText: 'Loading...',
47815 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
47819 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
47823 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
47824 * traditional select (defaults to true)
47828 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
47832 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
47836 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
47837 * listWidth has a higher value)
47841 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
47842 * allow the user to set arbitrary text into the field (defaults to false)
47844 forceSelection:false,
47846 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
47847 * if typeAhead = true (defaults to 250)
47849 typeAheadDelay : 250,
47851 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
47852 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
47854 valueNotFoundText : undefined,
47857 * @cfg {String} defaultValue The value displayed after loading the store.
47862 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
47864 blockFocus : false,
47867 * @cfg {Boolean} disableClear Disable showing of clear button.
47869 disableClear : false,
47871 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
47873 alwaysQuery : false,
47879 // element that contains real text value.. (when hidden is used..)
47882 onRender : function(ct, position){
47883 Roo.form.Field.prototype.onRender.call(this, ct, position);
47886 this.store.on('beforeload', this.onBeforeLoad, this);
47887 this.store.on('load', this.onLoad, this);
47888 this.store.on('loadexception', this.onLoadException, this);
47889 this.store.load({});
47897 initEvents : function(){
47898 //Roo.form.ComboBox.superclass.initEvents.call(this);
47902 onDestroy : function(){
47905 this.store.un('beforeload', this.onBeforeLoad, this);
47906 this.store.un('load', this.onLoad, this);
47907 this.store.un('loadexception', this.onLoadException, this);
47909 //Roo.form.ComboBox.superclass.onDestroy.call(this);
47913 fireKey : function(e){
47914 if(e.isNavKeyPress() && !this.list.isVisible()){
47915 this.fireEvent("specialkey", this, e);
47920 onResize: function(w, h){
47928 * Allow or prevent the user from directly editing the field text. If false is passed,
47929 * the user will only be able to select from the items defined in the dropdown list. This method
47930 * is the runtime equivalent of setting the 'editable' config option at config time.
47931 * @param {Boolean} value True to allow the user to directly edit the field text
47933 setEditable : function(value){
47938 onBeforeLoad : function(){
47940 Roo.log("Select before load");
47943 this.innerList.update(this.loadingText ?
47944 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
47945 //this.restrictHeight();
47946 this.selectedIndex = -1;
47950 onLoad : function(){
47953 var dom = this.el.dom;
47954 dom.innerHTML = '';
47955 var od = dom.ownerDocument;
47957 if (this.emptyText) {
47958 var op = od.createElement('option');
47959 op.setAttribute('value', '');
47960 op.innerHTML = String.format('{0}', this.emptyText);
47961 dom.appendChild(op);
47963 if(this.store.getCount() > 0){
47965 var vf = this.valueField;
47966 var df = this.displayField;
47967 this.store.data.each(function(r) {
47968 // which colmsn to use... testing - cdoe / title..
47969 var op = od.createElement('option');
47970 op.setAttribute('value', r.data[vf]);
47971 op.innerHTML = String.format('{0}', r.data[df]);
47972 dom.appendChild(op);
47974 if (typeof(this.defaultValue != 'undefined')) {
47975 this.setValue(this.defaultValue);
47980 //this.onEmptyResults();
47985 onLoadException : function()
47987 dom.innerHTML = '';
47989 Roo.log("Select on load exception");
47993 Roo.log(this.store.reader.jsonData);
47994 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
47995 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
48001 onTypeAhead : function(){
48006 onSelect : function(record, index){
48007 Roo.log('on select?');
48009 if(this.fireEvent('beforeselect', this, record, index) !== false){
48010 this.setFromData(index > -1 ? record.data : false);
48012 this.fireEvent('select', this, record, index);
48017 * Returns the currently selected field value or empty string if no value is set.
48018 * @return {String} value The selected value
48020 getValue : function(){
48021 var dom = this.el.dom;
48022 this.value = dom.options[dom.selectedIndex].value;
48028 * Clears any text/value currently set in the field
48030 clearValue : function(){
48032 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
48037 * Sets the specified value into the field. If the value finds a match, the corresponding record text
48038 * will be displayed in the field. If the value does not match the data value of an existing item,
48039 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
48040 * Otherwise the field will be blank (although the value will still be set).
48041 * @param {String} value The value to match
48043 setValue : function(v){
48044 var d = this.el.dom;
48045 for (var i =0; i < d.options.length;i++) {
48046 if (v == d.options[i].value) {
48047 d.selectedIndex = i;
48055 * @property {Object} the last set data for the element
48060 * Sets the value of the field based on a object which is related to the record format for the store.
48061 * @param {Object} value the value to set as. or false on reset?
48063 setFromData : function(o){
48064 Roo.log('setfrom data?');
48070 reset : function(){
48074 findRecord : function(prop, value){
48079 if(this.store.getCount() > 0){
48080 this.store.each(function(r){
48081 if(r.data[prop] == value){
48091 getName: function()
48093 // returns hidden if it's set..
48094 if (!this.rendered) {return ''};
48095 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
48103 onEmptyResults : function(){
48104 Roo.log('empty results');
48109 * Returns true if the dropdown list is expanded, else false.
48111 isExpanded : function(){
48116 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
48117 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48118 * @param {String} value The data value of the item to select
48119 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48120 * selected item if it is not currently in view (defaults to true)
48121 * @return {Boolean} True if the value matched an item in the list, else false
48123 selectByValue : function(v, scrollIntoView){
48124 Roo.log('select By Value');
48127 if(v !== undefined && v !== null){
48128 var r = this.findRecord(this.valueField || this.displayField, v);
48130 this.select(this.store.indexOf(r), scrollIntoView);
48138 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
48139 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48140 * @param {Number} index The zero-based index of the list item to select
48141 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48142 * selected item if it is not currently in view (defaults to true)
48144 select : function(index, scrollIntoView){
48145 Roo.log('select ');
48148 this.selectedIndex = index;
48149 this.view.select(index);
48150 if(scrollIntoView !== false){
48151 var el = this.view.getNode(index);
48153 this.innerList.scrollChildIntoView(el, false);
48161 validateBlur : function(){
48168 initQuery : function(){
48169 this.doQuery(this.getRawValue());
48173 doForce : function(){
48174 if(this.el.dom.value.length > 0){
48175 this.el.dom.value =
48176 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48182 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48183 * query allowing the query action to be canceled if needed.
48184 * @param {String} query The SQL query to execute
48185 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48186 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48187 * saved in the current store (defaults to false)
48189 doQuery : function(q, forceAll){
48191 Roo.log('doQuery?');
48192 if(q === undefined || q === null){
48197 forceAll: forceAll,
48201 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48205 forceAll = qe.forceAll;
48206 if(forceAll === true || (q.length >= this.minChars)){
48207 if(this.lastQuery != q || this.alwaysQuery){
48208 this.lastQuery = q;
48209 if(this.mode == 'local'){
48210 this.selectedIndex = -1;
48212 this.store.clearFilter();
48214 this.store.filter(this.displayField, q);
48218 this.store.baseParams[this.queryParam] = q;
48220 params: this.getParams(q)
48225 this.selectedIndex = -1;
48232 getParams : function(q){
48234 //p[this.queryParam] = q;
48237 p.limit = this.pageSize;
48243 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48245 collapse : function(){
48250 collapseIf : function(e){
48255 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48257 expand : function(){
48265 * @cfg {Boolean} grow
48269 * @cfg {Number} growMin
48273 * @cfg {Number} growMax
48281 setWidth : function()
48285 getResizeEl : function(){
48288 });//<script type="text/javasscript">
48292 * @class Roo.DDView
48293 * A DnD enabled version of Roo.View.
48294 * @param {Element/String} container The Element in which to create the View.
48295 * @param {String} tpl The template string used to create the markup for each element of the View
48296 * @param {Object} config The configuration properties. These include all the config options of
48297 * {@link Roo.View} plus some specific to this class.<br>
48299 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48300 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48302 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48303 .x-view-drag-insert-above {
48304 border-top:1px dotted #3366cc;
48306 .x-view-drag-insert-below {
48307 border-bottom:1px dotted #3366cc;
48313 Roo.DDView = function(container, tpl, config) {
48314 Roo.DDView.superclass.constructor.apply(this, arguments);
48315 this.getEl().setStyle("outline", "0px none");
48316 this.getEl().unselectable();
48317 if (this.dragGroup) {
48318 this.setDraggable(this.dragGroup.split(","));
48320 if (this.dropGroup) {
48321 this.setDroppable(this.dropGroup.split(","));
48323 if (this.deletable) {
48324 this.setDeletable();
48326 this.isDirtyFlag = false;
48332 Roo.extend(Roo.DDView, Roo.View, {
48333 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48334 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48335 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48336 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48340 reset: Roo.emptyFn,
48342 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48344 validate: function() {
48348 destroy: function() {
48349 this.purgeListeners();
48350 this.getEl.removeAllListeners();
48351 this.getEl().remove();
48352 if (this.dragZone) {
48353 if (this.dragZone.destroy) {
48354 this.dragZone.destroy();
48357 if (this.dropZone) {
48358 if (this.dropZone.destroy) {
48359 this.dropZone.destroy();
48364 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48365 getName: function() {
48369 /** Loads the View from a JSON string representing the Records to put into the Store. */
48370 setValue: function(v) {
48372 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48375 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48376 this.store.proxy = new Roo.data.MemoryProxy(data);
48380 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48381 getValue: function() {
48383 this.store.each(function(rec) {
48384 result += rec.id + ',';
48386 return result.substr(0, result.length - 1) + ')';
48389 getIds: function() {
48390 var i = 0, result = new Array(this.store.getCount());
48391 this.store.each(function(rec) {
48392 result[i++] = rec.id;
48397 isDirty: function() {
48398 return this.isDirtyFlag;
48402 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48403 * whole Element becomes the target, and this causes the drop gesture to append.
48405 getTargetFromEvent : function(e) {
48406 var target = e.getTarget();
48407 while ((target !== null) && (target.parentNode != this.el.dom)) {
48408 target = target.parentNode;
48411 target = this.el.dom.lastChild || this.el.dom;
48417 * Create the drag data which consists of an object which has the property "ddel" as
48418 * the drag proxy element.
48420 getDragData : function(e) {
48421 var target = this.findItemFromChild(e.getTarget());
48423 this.handleSelection(e);
48424 var selNodes = this.getSelectedNodes();
48427 copy: this.copy || (this.allowCopy && e.ctrlKey),
48431 var selectedIndices = this.getSelectedIndexes();
48432 for (var i = 0; i < selectedIndices.length; i++) {
48433 dragData.records.push(this.store.getAt(selectedIndices[i]));
48435 if (selNodes.length == 1) {
48436 dragData.ddel = target.cloneNode(true); // the div element
48438 var div = document.createElement('div'); // create the multi element drag "ghost"
48439 div.className = 'multi-proxy';
48440 for (var i = 0, len = selNodes.length; i < len; i++) {
48441 div.appendChild(selNodes[i].cloneNode(true));
48443 dragData.ddel = div;
48445 //console.log(dragData)
48446 //console.log(dragData.ddel.innerHTML)
48449 //console.log('nodragData')
48453 /** Specify to which ddGroup items in this DDView may be dragged. */
48454 setDraggable: function(ddGroup) {
48455 if (ddGroup instanceof Array) {
48456 Roo.each(ddGroup, this.setDraggable, this);
48459 if (this.dragZone) {
48460 this.dragZone.addToGroup(ddGroup);
48462 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48463 containerScroll: true,
48467 // Draggability implies selection. DragZone's mousedown selects the element.
48468 if (!this.multiSelect) { this.singleSelect = true; }
48470 // Wire the DragZone's handlers up to methods in *this*
48471 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48475 /** Specify from which ddGroup this DDView accepts drops. */
48476 setDroppable: function(ddGroup) {
48477 if (ddGroup instanceof Array) {
48478 Roo.each(ddGroup, this.setDroppable, this);
48481 if (this.dropZone) {
48482 this.dropZone.addToGroup(ddGroup);
48484 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48485 containerScroll: true,
48489 // Wire the DropZone's handlers up to methods in *this*
48490 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48491 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48492 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48493 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48494 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48498 /** Decide whether to drop above or below a View node. */
48499 getDropPoint : function(e, n, dd){
48500 if (n == this.el.dom) { return "above"; }
48501 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48502 var c = t + (b - t) / 2;
48503 var y = Roo.lib.Event.getPageY(e);
48511 onNodeEnter : function(n, dd, e, data){
48515 onNodeOver : function(n, dd, e, data){
48516 var pt = this.getDropPoint(e, n, dd);
48517 // set the insert point style on the target node
48518 var dragElClass = this.dropNotAllowed;
48521 if (pt == "above"){
48522 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48523 targetElClass = "x-view-drag-insert-above";
48525 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48526 targetElClass = "x-view-drag-insert-below";
48528 if (this.lastInsertClass != targetElClass){
48529 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48530 this.lastInsertClass = targetElClass;
48533 return dragElClass;
48536 onNodeOut : function(n, dd, e, data){
48537 this.removeDropIndicators(n);
48540 onNodeDrop : function(n, dd, e, data){
48541 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48544 var pt = this.getDropPoint(e, n, dd);
48545 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48546 if (pt == "below") { insertAt++; }
48547 for (var i = 0; i < data.records.length; i++) {
48548 var r = data.records[i];
48549 var dup = this.store.getById(r.id);
48550 if (dup && (dd != this.dragZone)) {
48551 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48554 this.store.insert(insertAt++, r.copy());
48556 data.source.isDirtyFlag = true;
48558 this.store.insert(insertAt++, r);
48560 this.isDirtyFlag = true;
48563 this.dragZone.cachedTarget = null;
48567 removeDropIndicators : function(n){
48569 Roo.fly(n).removeClass([
48570 "x-view-drag-insert-above",
48571 "x-view-drag-insert-below"]);
48572 this.lastInsertClass = "_noclass";
48577 * Utility method. Add a delete option to the DDView's context menu.
48578 * @param {String} imageUrl The URL of the "delete" icon image.
48580 setDeletable: function(imageUrl) {
48581 if (!this.singleSelect && !this.multiSelect) {
48582 this.singleSelect = true;
48584 var c = this.getContextMenu();
48585 this.contextMenu.on("itemclick", function(item) {
48588 this.remove(this.getSelectedIndexes());
48592 this.contextMenu.add({
48599 /** Return the context menu for this DDView. */
48600 getContextMenu: function() {
48601 if (!this.contextMenu) {
48602 // Create the View's context menu
48603 this.contextMenu = new Roo.menu.Menu({
48604 id: this.id + "-contextmenu"
48606 this.el.on("contextmenu", this.showContextMenu, this);
48608 return this.contextMenu;
48611 disableContextMenu: function() {
48612 if (this.contextMenu) {
48613 this.el.un("contextmenu", this.showContextMenu, this);
48617 showContextMenu: function(e, item) {
48618 item = this.findItemFromChild(e.getTarget());
48621 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
48622 this.contextMenu.showAt(e.getXY());
48627 * Remove {@link Roo.data.Record}s at the specified indices.
48628 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
48630 remove: function(selectedIndices) {
48631 selectedIndices = [].concat(selectedIndices);
48632 for (var i = 0; i < selectedIndices.length; i++) {
48633 var rec = this.store.getAt(selectedIndices[i]);
48634 this.store.remove(rec);
48639 * Double click fires the event, but also, if this is draggable, and there is only one other
48640 * related DropZone, it transfers the selected node.
48642 onDblClick : function(e){
48643 var item = this.findItemFromChild(e.getTarget());
48645 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
48648 if (this.dragGroup) {
48649 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
48650 while (targets.indexOf(this.dropZone) > -1) {
48651 targets.remove(this.dropZone);
48653 if (targets.length == 1) {
48654 this.dragZone.cachedTarget = null;
48655 var el = Roo.get(targets[0].getEl());
48656 var box = el.getBox(true);
48657 targets[0].onNodeDrop(el.dom, {
48659 xy: [box.x, box.y + box.height - 1]
48660 }, null, this.getDragData(e));
48666 handleSelection: function(e) {
48667 this.dragZone.cachedTarget = null;
48668 var item = this.findItemFromChild(e.getTarget());
48670 this.clearSelections(true);
48673 if (item && (this.multiSelect || this.singleSelect)){
48674 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
48675 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
48676 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
48677 this.unselect(item);
48679 this.select(item, this.multiSelect && e.ctrlKey);
48680 this.lastSelection = item;
48685 onItemClick : function(item, index, e){
48686 if(this.fireEvent("beforeclick", this, index, item, e) === false){
48692 unselect : function(nodeInfo, suppressEvent){
48693 var node = this.getNode(nodeInfo);
48694 if(node && this.isSelected(node)){
48695 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
48696 Roo.fly(node).removeClass(this.selectedClass);
48697 this.selections.remove(node);
48698 if(!suppressEvent){
48699 this.fireEvent("selectionchange", this, this.selections);
48707 * Ext JS Library 1.1.1
48708 * Copyright(c) 2006-2007, Ext JS, LLC.
48710 * Originally Released Under LGPL - original licence link has changed is not relivant.
48713 * <script type="text/javascript">
48717 * @class Roo.LayoutManager
48718 * @extends Roo.util.Observable
48719 * Base class for layout managers.
48721 Roo.LayoutManager = function(container, config){
48722 Roo.LayoutManager.superclass.constructor.call(this);
48723 this.el = Roo.get(container);
48724 // ie scrollbar fix
48725 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
48726 document.body.scroll = "no";
48727 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
48728 this.el.position('relative');
48730 this.id = this.el.id;
48731 this.el.addClass("x-layout-container");
48732 /** false to disable window resize monitoring @type Boolean */
48733 this.monitorWindowResize = true;
48738 * Fires when a layout is performed.
48739 * @param {Roo.LayoutManager} this
48743 * @event regionresized
48744 * Fires when the user resizes a region.
48745 * @param {Roo.LayoutRegion} region The resized region
48746 * @param {Number} newSize The new size (width for east/west, height for north/south)
48748 "regionresized" : true,
48750 * @event regioncollapsed
48751 * Fires when a region is collapsed.
48752 * @param {Roo.LayoutRegion} region The collapsed region
48754 "regioncollapsed" : true,
48756 * @event regionexpanded
48757 * Fires when a region is expanded.
48758 * @param {Roo.LayoutRegion} region The expanded region
48760 "regionexpanded" : true
48762 this.updating = false;
48763 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48766 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
48768 * Returns true if this layout is currently being updated
48769 * @return {Boolean}
48771 isUpdating : function(){
48772 return this.updating;
48776 * Suspend the LayoutManager from doing auto-layouts while
48777 * making multiple add or remove calls
48779 beginUpdate : function(){
48780 this.updating = true;
48784 * Restore auto-layouts and optionally disable the manager from performing a layout
48785 * @param {Boolean} noLayout true to disable a layout update
48787 endUpdate : function(noLayout){
48788 this.updating = false;
48794 layout: function(){
48798 onRegionResized : function(region, newSize){
48799 this.fireEvent("regionresized", region, newSize);
48803 onRegionCollapsed : function(region){
48804 this.fireEvent("regioncollapsed", region);
48807 onRegionExpanded : function(region){
48808 this.fireEvent("regionexpanded", region);
48812 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
48813 * performs box-model adjustments.
48814 * @return {Object} The size as an object {width: (the width), height: (the height)}
48816 getViewSize : function(){
48818 if(this.el.dom != document.body){
48819 size = this.el.getSize();
48821 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
48823 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
48824 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
48829 * Returns the Element this layout is bound to.
48830 * @return {Roo.Element}
48832 getEl : function(){
48837 * Returns the specified region.
48838 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
48839 * @return {Roo.LayoutRegion}
48841 getRegion : function(target){
48842 return this.regions[target.toLowerCase()];
48845 onWindowResize : function(){
48846 if(this.monitorWindowResize){
48852 * Ext JS Library 1.1.1
48853 * Copyright(c) 2006-2007, Ext JS, LLC.
48855 * Originally Released Under LGPL - original licence link has changed is not relivant.
48858 * <script type="text/javascript">
48861 * @class Roo.BorderLayout
48862 * @extends Roo.LayoutManager
48863 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
48864 * please see: <br><br>
48865 * <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>
48866 * <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>
48869 var layout = new Roo.BorderLayout(document.body, {
48903 preferredTabWidth: 150
48908 var CP = Roo.ContentPanel;
48910 layout.beginUpdate();
48911 layout.add("north", new CP("north", "North"));
48912 layout.add("south", new CP("south", {title: "South", closable: true}));
48913 layout.add("west", new CP("west", {title: "West"}));
48914 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
48915 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
48916 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
48917 layout.getRegion("center").showPanel("center1");
48918 layout.endUpdate();
48921 <b>The container the layout is rendered into can be either the body element or any other element.
48922 If it is not the body element, the container needs to either be an absolute positioned element,
48923 or you will need to add "position:relative" to the css of the container. You will also need to specify
48924 the container size if it is not the body element.</b>
48927 * Create a new BorderLayout
48928 * @param {String/HTMLElement/Element} container The container this layout is bound to
48929 * @param {Object} config Configuration options
48931 Roo.BorderLayout = function(container, config){
48932 config = config || {};
48933 Roo.BorderLayout.superclass.constructor.call(this, container, config);
48934 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
48935 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
48936 var target = this.factory.validRegions[i];
48937 if(config[target]){
48938 this.addRegion(target, config[target]);
48943 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
48945 * Creates and adds a new region if it doesn't already exist.
48946 * @param {String} target The target region key (north, south, east, west or center).
48947 * @param {Object} config The regions config object
48948 * @return {BorderLayoutRegion} The new region
48950 addRegion : function(target, config){
48951 if(!this.regions[target]){
48952 var r = this.factory.create(target, this, config);
48953 this.bindRegion(target, r);
48955 return this.regions[target];
48959 bindRegion : function(name, r){
48960 this.regions[name] = r;
48961 r.on("visibilitychange", this.layout, this);
48962 r.on("paneladded", this.layout, this);
48963 r.on("panelremoved", this.layout, this);
48964 r.on("invalidated", this.layout, this);
48965 r.on("resized", this.onRegionResized, this);
48966 r.on("collapsed", this.onRegionCollapsed, this);
48967 r.on("expanded", this.onRegionExpanded, this);
48971 * Performs a layout update.
48973 layout : function(){
48974 if(this.updating) return;
48975 var size = this.getViewSize();
48976 var w = size.width;
48977 var h = size.height;
48982 //var x = 0, y = 0;
48984 var rs = this.regions;
48985 var north = rs["north"];
48986 var south = rs["south"];
48987 var west = rs["west"];
48988 var east = rs["east"];
48989 var center = rs["center"];
48990 //if(this.hideOnLayout){ // not supported anymore
48991 //c.el.setStyle("display", "none");
48993 if(north && north.isVisible()){
48994 var b = north.getBox();
48995 var m = north.getMargins();
48996 b.width = w - (m.left+m.right);
48999 centerY = b.height + b.y + m.bottom;
49000 centerH -= centerY;
49001 north.updateBox(this.safeBox(b));
49003 if(south && south.isVisible()){
49004 var b = south.getBox();
49005 var m = south.getMargins();
49006 b.width = w - (m.left+m.right);
49008 var totalHeight = (b.height + m.top + m.bottom);
49009 b.y = h - totalHeight + m.top;
49010 centerH -= totalHeight;
49011 south.updateBox(this.safeBox(b));
49013 if(west && west.isVisible()){
49014 var b = west.getBox();
49015 var m = west.getMargins();
49016 b.height = centerH - (m.top+m.bottom);
49018 b.y = centerY + m.top;
49019 var totalWidth = (b.width + m.left + m.right);
49020 centerX += totalWidth;
49021 centerW -= totalWidth;
49022 west.updateBox(this.safeBox(b));
49024 if(east && east.isVisible()){
49025 var b = east.getBox();
49026 var m = east.getMargins();
49027 b.height = centerH - (m.top+m.bottom);
49028 var totalWidth = (b.width + m.left + m.right);
49029 b.x = w - totalWidth + m.left;
49030 b.y = centerY + m.top;
49031 centerW -= totalWidth;
49032 east.updateBox(this.safeBox(b));
49035 var m = center.getMargins();
49037 x: centerX + m.left,
49038 y: centerY + m.top,
49039 width: centerW - (m.left+m.right),
49040 height: centerH - (m.top+m.bottom)
49042 //if(this.hideOnLayout){
49043 //center.el.setStyle("display", "block");
49045 center.updateBox(this.safeBox(centerBox));
49048 this.fireEvent("layout", this);
49052 safeBox : function(box){
49053 box.width = Math.max(0, box.width);
49054 box.height = Math.max(0, box.height);
49059 * Adds a ContentPanel (or subclass) to this layout.
49060 * @param {String} target The target region key (north, south, east, west or center).
49061 * @param {Roo.ContentPanel} panel The panel to add
49062 * @return {Roo.ContentPanel} The added panel
49064 add : function(target, panel){
49066 target = target.toLowerCase();
49067 return this.regions[target].add(panel);
49071 * Remove a ContentPanel (or subclass) to this layout.
49072 * @param {String} target The target region key (north, south, east, west or center).
49073 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
49074 * @return {Roo.ContentPanel} The removed panel
49076 remove : function(target, panel){
49077 target = target.toLowerCase();
49078 return this.regions[target].remove(panel);
49082 * Searches all regions for a panel with the specified id
49083 * @param {String} panelId
49084 * @return {Roo.ContentPanel} The panel or null if it wasn't found
49086 findPanel : function(panelId){
49087 var rs = this.regions;
49088 for(var target in rs){
49089 if(typeof rs[target] != "function"){
49090 var p = rs[target].getPanel(panelId);
49100 * Searches all regions for a panel with the specified id and activates (shows) it.
49101 * @param {String/ContentPanel} panelId The panels id or the panel itself
49102 * @return {Roo.ContentPanel} The shown panel or null
49104 showPanel : function(panelId) {
49105 var rs = this.regions;
49106 for(var target in rs){
49107 var r = rs[target];
49108 if(typeof r != "function"){
49109 if(r.hasPanel(panelId)){
49110 return r.showPanel(panelId);
49118 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
49119 * @param {Roo.state.Provider} provider (optional) An alternate state provider
49121 restoreState : function(provider){
49123 provider = Roo.state.Manager;
49125 var sm = new Roo.LayoutStateManager();
49126 sm.init(this, provider);
49130 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
49131 * object should contain properties for each region to add ContentPanels to, and each property's value should be
49132 * a valid ContentPanel config object. Example:
49134 // Create the main layout
49135 var layout = new Roo.BorderLayout('main-ct', {
49146 // Create and add multiple ContentPanels at once via configs
49149 id: 'source-files',
49151 title:'Ext Source Files',
49164 * @param {Object} regions An object containing ContentPanel configs by region name
49166 batchAdd : function(regions){
49167 this.beginUpdate();
49168 for(var rname in regions){
49169 var lr = this.regions[rname];
49171 this.addTypedPanels(lr, regions[rname]);
49178 addTypedPanels : function(lr, ps){
49179 if(typeof ps == 'string'){
49180 lr.add(new Roo.ContentPanel(ps));
49182 else if(ps instanceof Array){
49183 for(var i =0, len = ps.length; i < len; i++){
49184 this.addTypedPanels(lr, ps[i]);
49187 else if(!ps.events){ // raw config?
49189 delete ps.el; // prevent conflict
49190 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49192 else { // panel object assumed!
49197 * Adds a xtype elements to the layout.
49201 xtype : 'ContentPanel',
49208 xtype : 'NestedLayoutPanel',
49214 items : [ ... list of content panels or nested layout panels.. ]
49218 * @param {Object} cfg Xtype definition of item to add.
49220 addxtype : function(cfg)
49222 // basically accepts a pannel...
49223 // can accept a layout region..!?!?
49224 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49226 if (!cfg.xtype.match(/Panel$/)) {
49231 if (typeof(cfg.region) == 'undefined') {
49232 Roo.log("Failed to add Panel, region was not set");
49236 var region = cfg.region;
49242 xitems = cfg.items;
49249 case 'ContentPanel': // ContentPanel (el, cfg)
49250 case 'ScrollPanel': // ContentPanel (el, cfg)
49252 if(cfg.autoCreate) {
49253 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49255 var el = this.el.createChild();
49256 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49259 this.add(region, ret);
49263 case 'TreePanel': // our new panel!
49264 cfg.el = this.el.createChild();
49265 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49266 this.add(region, ret);
49269 case 'NestedLayoutPanel':
49270 // create a new Layout (which is a Border Layout...
49271 var el = this.el.createChild();
49272 var clayout = cfg.layout;
49274 clayout.items = clayout.items || [];
49275 // replace this exitems with the clayout ones..
49276 xitems = clayout.items;
49279 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49280 cfg.background = false;
49282 var layout = new Roo.BorderLayout(el, clayout);
49284 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49285 //console.log('adding nested layout panel ' + cfg.toSource());
49286 this.add(region, ret);
49287 nb = {}; /// find first...
49292 // needs grid and region
49294 //var el = this.getRegion(region).el.createChild();
49295 var el = this.el.createChild();
49296 // create the grid first...
49298 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49300 if (region == 'center' && this.active ) {
49301 cfg.background = false;
49303 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49305 this.add(region, ret);
49306 if (cfg.background) {
49307 ret.on('activate', function(gp) {
49308 if (!gp.grid.rendered) {
49323 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49325 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49326 this.add(region, ret);
49329 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49333 // GridPanel (grid, cfg)
49336 this.beginUpdate();
49340 Roo.each(xitems, function(i) {
49341 region = nb && i.region ? i.region : false;
49343 var add = ret.addxtype(i);
49346 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49347 if (!i.background) {
49348 abn[region] = nb[region] ;
49355 // make the last non-background panel active..
49356 //if (nb) { Roo.log(abn); }
49359 for(var r in abn) {
49360 region = this.getRegion(r);
49362 // tried using nb[r], but it does not work..
49364 region.showPanel(abn[r]);
49375 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49376 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49377 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49378 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49381 var CP = Roo.ContentPanel;
49383 var layout = Roo.BorderLayout.create({
49387 panels: [new CP("north", "North")]
49396 panels: [new CP("west", {title: "West"})]
49405 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49414 panels: [new CP("south", {title: "South", closable: true})]
49421 preferredTabWidth: 150,
49423 new CP("center1", {title: "Close Me", closable: true}),
49424 new CP("center2", {title: "Center Panel", closable: false})
49429 layout.getRegion("center").showPanel("center1");
49434 Roo.BorderLayout.create = function(config, targetEl){
49435 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49436 layout.beginUpdate();
49437 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49438 for(var j = 0, jlen = regions.length; j < jlen; j++){
49439 var lr = regions[j];
49440 if(layout.regions[lr] && config[lr].panels){
49441 var r = layout.regions[lr];
49442 var ps = config[lr].panels;
49443 layout.addTypedPanels(r, ps);
49446 layout.endUpdate();
49451 Roo.BorderLayout.RegionFactory = {
49453 validRegions : ["north","south","east","west","center"],
49456 create : function(target, mgr, config){
49457 target = target.toLowerCase();
49458 if(config.lightweight || config.basic){
49459 return new Roo.BasicLayoutRegion(mgr, config, target);
49463 return new Roo.NorthLayoutRegion(mgr, config);
49465 return new Roo.SouthLayoutRegion(mgr, config);
49467 return new Roo.EastLayoutRegion(mgr, config);
49469 return new Roo.WestLayoutRegion(mgr, config);
49471 return new Roo.CenterLayoutRegion(mgr, config);
49473 throw 'Layout region "'+target+'" not supported.';
49477 * Ext JS Library 1.1.1
49478 * Copyright(c) 2006-2007, Ext JS, LLC.
49480 * Originally Released Under LGPL - original licence link has changed is not relivant.
49483 * <script type="text/javascript">
49487 * @class Roo.BasicLayoutRegion
49488 * @extends Roo.util.Observable
49489 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49490 * and does not have a titlebar, tabs or any other features. All it does is size and position
49491 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49493 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49495 this.position = pos;
49498 * @scope Roo.BasicLayoutRegion
49502 * @event beforeremove
49503 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49504 * @param {Roo.LayoutRegion} this
49505 * @param {Roo.ContentPanel} panel The panel
49506 * @param {Object} e The cancel event object
49508 "beforeremove" : true,
49510 * @event invalidated
49511 * Fires when the layout for this region is changed.
49512 * @param {Roo.LayoutRegion} this
49514 "invalidated" : true,
49516 * @event visibilitychange
49517 * Fires when this region is shown or hidden
49518 * @param {Roo.LayoutRegion} this
49519 * @param {Boolean} visibility true or false
49521 "visibilitychange" : true,
49523 * @event paneladded
49524 * Fires when a panel is added.
49525 * @param {Roo.LayoutRegion} this
49526 * @param {Roo.ContentPanel} panel The panel
49528 "paneladded" : true,
49530 * @event panelremoved
49531 * Fires when a panel is removed.
49532 * @param {Roo.LayoutRegion} this
49533 * @param {Roo.ContentPanel} panel The panel
49535 "panelremoved" : true,
49538 * Fires when this region is collapsed.
49539 * @param {Roo.LayoutRegion} this
49541 "collapsed" : true,
49544 * Fires when this region is expanded.
49545 * @param {Roo.LayoutRegion} this
49550 * Fires when this region is slid into view.
49551 * @param {Roo.LayoutRegion} this
49553 "slideshow" : true,
49556 * Fires when this region slides out of view.
49557 * @param {Roo.LayoutRegion} this
49559 "slidehide" : true,
49561 * @event panelactivated
49562 * Fires when a panel is activated.
49563 * @param {Roo.LayoutRegion} this
49564 * @param {Roo.ContentPanel} panel The activated panel
49566 "panelactivated" : true,
49569 * Fires when the user resizes this region.
49570 * @param {Roo.LayoutRegion} this
49571 * @param {Number} newSize The new size (width for east/west, height for north/south)
49575 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49576 this.panels = new Roo.util.MixedCollection();
49577 this.panels.getKey = this.getPanelId.createDelegate(this);
49579 this.activePanel = null;
49580 // ensure listeners are added...
49582 if (config.listeners || config.events) {
49583 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49584 listeners : config.listeners || {},
49585 events : config.events || {}
49589 if(skipConfig !== true){
49590 this.applyConfig(config);
49594 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49595 getPanelId : function(p){
49599 applyConfig : function(config){
49600 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49601 this.config = config;
49606 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49607 * the width, for horizontal (north, south) the height.
49608 * @param {Number} newSize The new width or height
49610 resizeTo : function(newSize){
49611 var el = this.el ? this.el :
49612 (this.activePanel ? this.activePanel.getEl() : null);
49614 switch(this.position){
49617 el.setWidth(newSize);
49618 this.fireEvent("resized", this, newSize);
49622 el.setHeight(newSize);
49623 this.fireEvent("resized", this, newSize);
49629 getBox : function(){
49630 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
49633 getMargins : function(){
49634 return this.margins;
49637 updateBox : function(box){
49639 var el = this.activePanel.getEl();
49640 el.dom.style.left = box.x + "px";
49641 el.dom.style.top = box.y + "px";
49642 this.activePanel.setSize(box.width, box.height);
49646 * Returns the container element for this region.
49647 * @return {Roo.Element}
49649 getEl : function(){
49650 return this.activePanel;
49654 * Returns true if this region is currently visible.
49655 * @return {Boolean}
49657 isVisible : function(){
49658 return this.activePanel ? true : false;
49661 setActivePanel : function(panel){
49662 panel = this.getPanel(panel);
49663 if(this.activePanel && this.activePanel != panel){
49664 this.activePanel.setActiveState(false);
49665 this.activePanel.getEl().setLeftTop(-10000,-10000);
49667 this.activePanel = panel;
49668 panel.setActiveState(true);
49670 panel.setSize(this.box.width, this.box.height);
49672 this.fireEvent("panelactivated", this, panel);
49673 this.fireEvent("invalidated");
49677 * Show the specified panel.
49678 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
49679 * @return {Roo.ContentPanel} The shown panel or null
49681 showPanel : function(panel){
49682 if(panel = this.getPanel(panel)){
49683 this.setActivePanel(panel);
49689 * Get the active panel for this region.
49690 * @return {Roo.ContentPanel} The active panel or null
49692 getActivePanel : function(){
49693 return this.activePanel;
49697 * Add the passed ContentPanel(s)
49698 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49699 * @return {Roo.ContentPanel} The panel added (if only one was added)
49701 add : function(panel){
49702 if(arguments.length > 1){
49703 for(var i = 0, len = arguments.length; i < len; i++) {
49704 this.add(arguments[i]);
49708 if(this.hasPanel(panel)){
49709 this.showPanel(panel);
49712 var el = panel.getEl();
49713 if(el.dom.parentNode != this.mgr.el.dom){
49714 this.mgr.el.dom.appendChild(el.dom);
49716 if(panel.setRegion){
49717 panel.setRegion(this);
49719 this.panels.add(panel);
49720 el.setStyle("position", "absolute");
49721 if(!panel.background){
49722 this.setActivePanel(panel);
49723 if(this.config.initialSize && this.panels.getCount()==1){
49724 this.resizeTo(this.config.initialSize);
49727 this.fireEvent("paneladded", this, panel);
49732 * Returns true if the panel is in this region.
49733 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49734 * @return {Boolean}
49736 hasPanel : function(panel){
49737 if(typeof panel == "object"){ // must be panel obj
49738 panel = panel.getId();
49740 return this.getPanel(panel) ? true : false;
49744 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49745 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49746 * @param {Boolean} preservePanel Overrides the config preservePanel option
49747 * @return {Roo.ContentPanel} The panel that was removed
49749 remove : function(panel, preservePanel){
49750 panel = this.getPanel(panel);
49755 this.fireEvent("beforeremove", this, panel, e);
49756 if(e.cancel === true){
49759 var panelId = panel.getId();
49760 this.panels.removeKey(panelId);
49765 * Returns the panel specified or null if it's not in this region.
49766 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49767 * @return {Roo.ContentPanel}
49769 getPanel : function(id){
49770 if(typeof id == "object"){ // must be panel obj
49773 return this.panels.get(id);
49777 * Returns this regions position (north/south/east/west/center).
49780 getPosition: function(){
49781 return this.position;
49785 * Ext JS Library 1.1.1
49786 * Copyright(c) 2006-2007, Ext JS, LLC.
49788 * Originally Released Under LGPL - original licence link has changed is not relivant.
49791 * <script type="text/javascript">
49795 * @class Roo.LayoutRegion
49796 * @extends Roo.BasicLayoutRegion
49797 * This class represents a region in a layout manager.
49798 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
49799 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
49800 * @cfg {Boolean} floatable False to disable floating (defaults to true)
49801 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
49802 * @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})
49803 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
49804 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
49805 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
49806 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
49807 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
49808 * @cfg {String} title The title for the region (overrides panel titles)
49809 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
49810 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
49811 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
49812 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
49813 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
49814 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
49815 * the space available, similar to FireFox 1.5 tabs (defaults to false)
49816 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
49817 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
49818 * @cfg {Boolean} showPin True to show a pin button
49819 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
49820 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
49821 * @cfg {Boolean} disableTabTips True to disable tab tooltips
49822 * @cfg {Number} width For East/West panels
49823 * @cfg {Number} height For North/South panels
49824 * @cfg {Boolean} split To show the splitter
49825 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
49827 Roo.LayoutRegion = function(mgr, config, pos){
49828 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
49829 var dh = Roo.DomHelper;
49830 /** This region's container element
49831 * @type Roo.Element */
49832 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
49833 /** This region's title element
49834 * @type Roo.Element */
49836 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
49837 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
49838 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
49840 this.titleEl.enableDisplayMode();
49841 /** This region's title text element
49842 * @type HTMLElement */
49843 this.titleTextEl = this.titleEl.dom.firstChild;
49844 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
49845 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
49846 this.closeBtn.enableDisplayMode();
49847 this.closeBtn.on("click", this.closeClicked, this);
49848 this.closeBtn.hide();
49850 this.createBody(config);
49851 this.visible = true;
49852 this.collapsed = false;
49854 if(config.hideWhenEmpty){
49856 this.on("paneladded", this.validateVisibility, this);
49857 this.on("panelremoved", this.validateVisibility, this);
49859 this.applyConfig(config);
49862 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
49864 createBody : function(){
49865 /** This region's body element
49866 * @type Roo.Element */
49867 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
49870 applyConfig : function(c){
49871 if(c.collapsible && this.position != "center" && !this.collapsedEl){
49872 var dh = Roo.DomHelper;
49873 if(c.titlebar !== false){
49874 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
49875 this.collapseBtn.on("click", this.collapse, this);
49876 this.collapseBtn.enableDisplayMode();
49878 if(c.showPin === true || this.showPin){
49879 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
49880 this.stickBtn.enableDisplayMode();
49881 this.stickBtn.on("click", this.expand, this);
49882 this.stickBtn.hide();
49885 /** This region's collapsed element
49886 * @type Roo.Element */
49887 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
49888 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
49890 if(c.floatable !== false){
49891 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
49892 this.collapsedEl.on("click", this.collapseClick, this);
49895 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
49896 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
49897 id: "message", unselectable: "on", style:{"float":"left"}});
49898 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
49900 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
49901 this.expandBtn.on("click", this.expand, this);
49903 if(this.collapseBtn){
49904 this.collapseBtn.setVisible(c.collapsible == true);
49906 this.cmargins = c.cmargins || this.cmargins ||
49907 (this.position == "west" || this.position == "east" ?
49908 {top: 0, left: 2, right:2, bottom: 0} :
49909 {top: 2, left: 0, right:0, bottom: 2});
49910 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49911 this.bottomTabs = c.tabPosition != "top";
49912 this.autoScroll = c.autoScroll || false;
49913 if(this.autoScroll){
49914 this.bodyEl.setStyle("overflow", "auto");
49916 this.bodyEl.setStyle("overflow", "hidden");
49918 //if(c.titlebar !== false){
49919 if((!c.titlebar && !c.title) || c.titlebar === false){
49920 this.titleEl.hide();
49922 this.titleEl.show();
49924 this.titleTextEl.innerHTML = c.title;
49928 this.duration = c.duration || .30;
49929 this.slideDuration = c.slideDuration || .45;
49932 this.collapse(true);
49939 * Returns true if this region is currently visible.
49940 * @return {Boolean}
49942 isVisible : function(){
49943 return this.visible;
49947 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
49948 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
49950 setCollapsedTitle : function(title){
49951 title = title || " ";
49952 if(this.collapsedTitleTextEl){
49953 this.collapsedTitleTextEl.innerHTML = title;
49957 getBox : function(){
49959 if(!this.collapsed){
49960 b = this.el.getBox(false, true);
49962 b = this.collapsedEl.getBox(false, true);
49967 getMargins : function(){
49968 return this.collapsed ? this.cmargins : this.margins;
49971 highlight : function(){
49972 this.el.addClass("x-layout-panel-dragover");
49975 unhighlight : function(){
49976 this.el.removeClass("x-layout-panel-dragover");
49979 updateBox : function(box){
49981 if(!this.collapsed){
49982 this.el.dom.style.left = box.x + "px";
49983 this.el.dom.style.top = box.y + "px";
49984 this.updateBody(box.width, box.height);
49986 this.collapsedEl.dom.style.left = box.x + "px";
49987 this.collapsedEl.dom.style.top = box.y + "px";
49988 this.collapsedEl.setSize(box.width, box.height);
49991 this.tabs.autoSizeTabs();
49995 updateBody : function(w, h){
49997 this.el.setWidth(w);
49998 w -= this.el.getBorderWidth("rl");
49999 if(this.config.adjustments){
50000 w += this.config.adjustments[0];
50004 this.el.setHeight(h);
50005 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
50006 h -= this.el.getBorderWidth("tb");
50007 if(this.config.adjustments){
50008 h += this.config.adjustments[1];
50010 this.bodyEl.setHeight(h);
50012 h = this.tabs.syncHeight(h);
50015 if(this.panelSize){
50016 w = w !== null ? w : this.panelSize.width;
50017 h = h !== null ? h : this.panelSize.height;
50019 if(this.activePanel){
50020 var el = this.activePanel.getEl();
50021 w = w !== null ? w : el.getWidth();
50022 h = h !== null ? h : el.getHeight();
50023 this.panelSize = {width: w, height: h};
50024 this.activePanel.setSize(w, h);
50026 if(Roo.isIE && this.tabs){
50027 this.tabs.el.repaint();
50032 * Returns the container element for this region.
50033 * @return {Roo.Element}
50035 getEl : function(){
50040 * Hides this region.
50043 if(!this.collapsed){
50044 this.el.dom.style.left = "-2000px";
50047 this.collapsedEl.dom.style.left = "-2000px";
50048 this.collapsedEl.hide();
50050 this.visible = false;
50051 this.fireEvent("visibilitychange", this, false);
50055 * Shows this region if it was previously hidden.
50058 if(!this.collapsed){
50061 this.collapsedEl.show();
50063 this.visible = true;
50064 this.fireEvent("visibilitychange", this, true);
50067 closeClicked : function(){
50068 if(this.activePanel){
50069 this.remove(this.activePanel);
50073 collapseClick : function(e){
50075 e.stopPropagation();
50078 e.stopPropagation();
50084 * Collapses this region.
50085 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
50087 collapse : function(skipAnim){
50088 if(this.collapsed) return;
50089 this.collapsed = true;
50091 this.split.el.hide();
50093 if(this.config.animate && skipAnim !== true){
50094 this.fireEvent("invalidated", this);
50095 this.animateCollapse();
50097 this.el.setLocation(-20000,-20000);
50099 this.collapsedEl.show();
50100 this.fireEvent("collapsed", this);
50101 this.fireEvent("invalidated", this);
50105 animateCollapse : function(){
50110 * Expands this region if it was previously collapsed.
50111 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
50112 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
50114 expand : function(e, skipAnim){
50115 if(e) e.stopPropagation();
50116 if(!this.collapsed || this.el.hasActiveFx()) return;
50118 this.afterSlideIn();
50121 this.collapsed = false;
50122 if(this.config.animate && skipAnim !== true){
50123 this.animateExpand();
50127 this.split.el.show();
50129 this.collapsedEl.setLocation(-2000,-2000);
50130 this.collapsedEl.hide();
50131 this.fireEvent("invalidated", this);
50132 this.fireEvent("expanded", this);
50136 animateExpand : function(){
50140 initTabs : function()
50142 this.bodyEl.setStyle("overflow", "hidden");
50143 var ts = new Roo.TabPanel(
50146 tabPosition: this.bottomTabs ? 'bottom' : 'top',
50147 disableTooltips: this.config.disableTabTips,
50148 toolbar : this.config.toolbar
50151 if(this.config.hideTabs){
50152 ts.stripWrap.setDisplayed(false);
50155 ts.resizeTabs = this.config.resizeTabs === true;
50156 ts.minTabWidth = this.config.minTabWidth || 40;
50157 ts.maxTabWidth = this.config.maxTabWidth || 250;
50158 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
50159 ts.monitorResize = false;
50160 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50161 ts.bodyEl.addClass('x-layout-tabs-body');
50162 this.panels.each(this.initPanelAsTab, this);
50165 initPanelAsTab : function(panel){
50166 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50167 this.config.closeOnTab && panel.isClosable());
50168 if(panel.tabTip !== undefined){
50169 ti.setTooltip(panel.tabTip);
50171 ti.on("activate", function(){
50172 this.setActivePanel(panel);
50174 if(this.config.closeOnTab){
50175 ti.on("beforeclose", function(t, e){
50177 this.remove(panel);
50183 updatePanelTitle : function(panel, title){
50184 if(this.activePanel == panel){
50185 this.updateTitle(title);
50188 var ti = this.tabs.getTab(panel.getEl().id);
50190 if(panel.tabTip !== undefined){
50191 ti.setTooltip(panel.tabTip);
50196 updateTitle : function(title){
50197 if(this.titleTextEl && !this.config.title){
50198 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50202 setActivePanel : function(panel){
50203 panel = this.getPanel(panel);
50204 if(this.activePanel && this.activePanel != panel){
50205 this.activePanel.setActiveState(false);
50207 this.activePanel = panel;
50208 panel.setActiveState(true);
50209 if(this.panelSize){
50210 panel.setSize(this.panelSize.width, this.panelSize.height);
50213 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50215 this.updateTitle(panel.getTitle());
50217 this.fireEvent("invalidated", this);
50219 this.fireEvent("panelactivated", this, panel);
50223 * Shows the specified panel.
50224 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50225 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50227 showPanel : function(panel){
50228 if(panel = this.getPanel(panel)){
50230 var tab = this.tabs.getTab(panel.getEl().id);
50231 if(tab.isHidden()){
50232 this.tabs.unhideTab(tab.id);
50236 this.setActivePanel(panel);
50243 * Get the active panel for this region.
50244 * @return {Roo.ContentPanel} The active panel or null
50246 getActivePanel : function(){
50247 return this.activePanel;
50250 validateVisibility : function(){
50251 if(this.panels.getCount() < 1){
50252 this.updateTitle(" ");
50253 this.closeBtn.hide();
50256 if(!this.isVisible()){
50263 * Adds the passed ContentPanel(s) to this region.
50264 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50265 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50267 add : function(panel){
50268 if(arguments.length > 1){
50269 for(var i = 0, len = arguments.length; i < len; i++) {
50270 this.add(arguments[i]);
50274 if(this.hasPanel(panel)){
50275 this.showPanel(panel);
50278 panel.setRegion(this);
50279 this.panels.add(panel);
50280 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50281 this.bodyEl.dom.appendChild(panel.getEl().dom);
50282 if(panel.background !== true){
50283 this.setActivePanel(panel);
50285 this.fireEvent("paneladded", this, panel);
50291 this.initPanelAsTab(panel);
50293 if(panel.background !== true){
50294 this.tabs.activate(panel.getEl().id);
50296 this.fireEvent("paneladded", this, panel);
50301 * Hides the tab for the specified panel.
50302 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50304 hidePanel : function(panel){
50305 if(this.tabs && (panel = this.getPanel(panel))){
50306 this.tabs.hideTab(panel.getEl().id);
50311 * Unhides the tab for a previously hidden panel.
50312 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50314 unhidePanel : function(panel){
50315 if(this.tabs && (panel = this.getPanel(panel))){
50316 this.tabs.unhideTab(panel.getEl().id);
50320 clearPanels : function(){
50321 while(this.panels.getCount() > 0){
50322 this.remove(this.panels.first());
50327 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50328 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50329 * @param {Boolean} preservePanel Overrides the config preservePanel option
50330 * @return {Roo.ContentPanel} The panel that was removed
50332 remove : function(panel, preservePanel){
50333 panel = this.getPanel(panel);
50338 this.fireEvent("beforeremove", this, panel, e);
50339 if(e.cancel === true){
50342 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50343 var panelId = panel.getId();
50344 this.panels.removeKey(panelId);
50346 document.body.appendChild(panel.getEl().dom);
50349 this.tabs.removeTab(panel.getEl().id);
50350 }else if (!preservePanel){
50351 this.bodyEl.dom.removeChild(panel.getEl().dom);
50353 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50354 var p = this.panels.first();
50355 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50356 tempEl.appendChild(p.getEl().dom);
50357 this.bodyEl.update("");
50358 this.bodyEl.dom.appendChild(p.getEl().dom);
50360 this.updateTitle(p.getTitle());
50362 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50363 this.setActivePanel(p);
50365 panel.setRegion(null);
50366 if(this.activePanel == panel){
50367 this.activePanel = null;
50369 if(this.config.autoDestroy !== false && preservePanel !== true){
50370 try{panel.destroy();}catch(e){}
50372 this.fireEvent("panelremoved", this, panel);
50377 * Returns the TabPanel component used by this region
50378 * @return {Roo.TabPanel}
50380 getTabs : function(){
50384 createTool : function(parentEl, className){
50385 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50386 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50387 btn.addClassOnOver("x-layout-tools-button-over");
50392 * Ext JS Library 1.1.1
50393 * Copyright(c) 2006-2007, Ext JS, LLC.
50395 * Originally Released Under LGPL - original licence link has changed is not relivant.
50398 * <script type="text/javascript">
50404 * @class Roo.SplitLayoutRegion
50405 * @extends Roo.LayoutRegion
50406 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50408 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50409 this.cursor = cursor;
50410 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50413 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50414 splitTip : "Drag to resize.",
50415 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50416 useSplitTips : false,
50418 applyConfig : function(config){
50419 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50422 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50423 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50424 /** The SplitBar for this region
50425 * @type Roo.SplitBar */
50426 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50427 this.split.on("moved", this.onSplitMove, this);
50428 this.split.useShim = config.useShim === true;
50429 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50430 if(this.useSplitTips){
50431 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50433 if(config.collapsible){
50434 this.split.el.on("dblclick", this.collapse, this);
50437 if(typeof config.minSize != "undefined"){
50438 this.split.minSize = config.minSize;
50440 if(typeof config.maxSize != "undefined"){
50441 this.split.maxSize = config.maxSize;
50443 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50444 this.hideSplitter();
50449 getHMaxSize : function(){
50450 var cmax = this.config.maxSize || 10000;
50451 var center = this.mgr.getRegion("center");
50452 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50455 getVMaxSize : function(){
50456 var cmax = this.config.maxSize || 10000;
50457 var center = this.mgr.getRegion("center");
50458 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50461 onSplitMove : function(split, newSize){
50462 this.fireEvent("resized", this, newSize);
50466 * Returns the {@link Roo.SplitBar} for this region.
50467 * @return {Roo.SplitBar}
50469 getSplitBar : function(){
50474 this.hideSplitter();
50475 Roo.SplitLayoutRegion.superclass.hide.call(this);
50478 hideSplitter : function(){
50480 this.split.el.setLocation(-2000,-2000);
50481 this.split.el.hide();
50487 this.split.el.show();
50489 Roo.SplitLayoutRegion.superclass.show.call(this);
50492 beforeSlide: function(){
50493 if(Roo.isGecko){// firefox overflow auto bug workaround
50494 this.bodyEl.clip();
50495 if(this.tabs) this.tabs.bodyEl.clip();
50496 if(this.activePanel){
50497 this.activePanel.getEl().clip();
50499 if(this.activePanel.beforeSlide){
50500 this.activePanel.beforeSlide();
50506 afterSlide : function(){
50507 if(Roo.isGecko){// firefox overflow auto bug workaround
50508 this.bodyEl.unclip();
50509 if(this.tabs) this.tabs.bodyEl.unclip();
50510 if(this.activePanel){
50511 this.activePanel.getEl().unclip();
50512 if(this.activePanel.afterSlide){
50513 this.activePanel.afterSlide();
50519 initAutoHide : function(){
50520 if(this.autoHide !== false){
50521 if(!this.autoHideHd){
50522 var st = new Roo.util.DelayedTask(this.slideIn, this);
50523 this.autoHideHd = {
50524 "mouseout": function(e){
50525 if(!e.within(this.el, true)){
50529 "mouseover" : function(e){
50535 this.el.on(this.autoHideHd);
50539 clearAutoHide : function(){
50540 if(this.autoHide !== false){
50541 this.el.un("mouseout", this.autoHideHd.mouseout);
50542 this.el.un("mouseover", this.autoHideHd.mouseover);
50546 clearMonitor : function(){
50547 Roo.get(document).un("click", this.slideInIf, this);
50550 // these names are backwards but not changed for compat
50551 slideOut : function(){
50552 if(this.isSlid || this.el.hasActiveFx()){
50555 this.isSlid = true;
50556 if(this.collapseBtn){
50557 this.collapseBtn.hide();
50559 this.closeBtnState = this.closeBtn.getStyle('display');
50560 this.closeBtn.hide();
50562 this.stickBtn.show();
50565 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50566 this.beforeSlide();
50567 this.el.setStyle("z-index", 10001);
50568 this.el.slideIn(this.getSlideAnchor(), {
50569 callback: function(){
50571 this.initAutoHide();
50572 Roo.get(document).on("click", this.slideInIf, this);
50573 this.fireEvent("slideshow", this);
50580 afterSlideIn : function(){
50581 this.clearAutoHide();
50582 this.isSlid = false;
50583 this.clearMonitor();
50584 this.el.setStyle("z-index", "");
50585 if(this.collapseBtn){
50586 this.collapseBtn.show();
50588 this.closeBtn.setStyle('display', this.closeBtnState);
50590 this.stickBtn.hide();
50592 this.fireEvent("slidehide", this);
50595 slideIn : function(cb){
50596 if(!this.isSlid || this.el.hasActiveFx()){
50600 this.isSlid = false;
50601 this.beforeSlide();
50602 this.el.slideOut(this.getSlideAnchor(), {
50603 callback: function(){
50604 this.el.setLeftTop(-10000, -10000);
50606 this.afterSlideIn();
50614 slideInIf : function(e){
50615 if(!e.within(this.el)){
50620 animateCollapse : function(){
50621 this.beforeSlide();
50622 this.el.setStyle("z-index", 20000);
50623 var anchor = this.getSlideAnchor();
50624 this.el.slideOut(anchor, {
50625 callback : function(){
50626 this.el.setStyle("z-index", "");
50627 this.collapsedEl.slideIn(anchor, {duration:.3});
50629 this.el.setLocation(-10000,-10000);
50631 this.fireEvent("collapsed", this);
50638 animateExpand : function(){
50639 this.beforeSlide();
50640 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
50641 this.el.setStyle("z-index", 20000);
50642 this.collapsedEl.hide({
50645 this.el.slideIn(this.getSlideAnchor(), {
50646 callback : function(){
50647 this.el.setStyle("z-index", "");
50650 this.split.el.show();
50652 this.fireEvent("invalidated", this);
50653 this.fireEvent("expanded", this);
50681 getAnchor : function(){
50682 return this.anchors[this.position];
50685 getCollapseAnchor : function(){
50686 return this.canchors[this.position];
50689 getSlideAnchor : function(){
50690 return this.sanchors[this.position];
50693 getAlignAdj : function(){
50694 var cm = this.cmargins;
50695 switch(this.position){
50711 getExpandAdj : function(){
50712 var c = this.collapsedEl, cm = this.cmargins;
50713 switch(this.position){
50715 return [-(cm.right+c.getWidth()+cm.left), 0];
50718 return [cm.right+c.getWidth()+cm.left, 0];
50721 return [0, -(cm.top+cm.bottom+c.getHeight())];
50724 return [0, cm.top+cm.bottom+c.getHeight()];
50730 * Ext JS Library 1.1.1
50731 * Copyright(c) 2006-2007, Ext JS, LLC.
50733 * Originally Released Under LGPL - original licence link has changed is not relivant.
50736 * <script type="text/javascript">
50739 * These classes are private internal classes
50741 Roo.CenterLayoutRegion = function(mgr, config){
50742 Roo.LayoutRegion.call(this, mgr, config, "center");
50743 this.visible = true;
50744 this.minWidth = config.minWidth || 20;
50745 this.minHeight = config.minHeight || 20;
50748 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
50750 // center panel can't be hidden
50754 // center panel can't be hidden
50757 getMinWidth: function(){
50758 return this.minWidth;
50761 getMinHeight: function(){
50762 return this.minHeight;
50767 Roo.NorthLayoutRegion = function(mgr, config){
50768 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
50770 this.split.placement = Roo.SplitBar.TOP;
50771 this.split.orientation = Roo.SplitBar.VERTICAL;
50772 this.split.el.addClass("x-layout-split-v");
50774 var size = config.initialSize || config.height;
50775 if(typeof size != "undefined"){
50776 this.el.setHeight(size);
50779 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
50780 orientation: Roo.SplitBar.VERTICAL,
50781 getBox : function(){
50782 if(this.collapsed){
50783 return this.collapsedEl.getBox();
50785 var box = this.el.getBox();
50787 box.height += this.split.el.getHeight();
50792 updateBox : function(box){
50793 if(this.split && !this.collapsed){
50794 box.height -= this.split.el.getHeight();
50795 this.split.el.setLeft(box.x);
50796 this.split.el.setTop(box.y+box.height);
50797 this.split.el.setWidth(box.width);
50799 if(this.collapsed){
50800 this.updateBody(box.width, null);
50802 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50806 Roo.SouthLayoutRegion = function(mgr, config){
50807 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
50809 this.split.placement = Roo.SplitBar.BOTTOM;
50810 this.split.orientation = Roo.SplitBar.VERTICAL;
50811 this.split.el.addClass("x-layout-split-v");
50813 var size = config.initialSize || config.height;
50814 if(typeof size != "undefined"){
50815 this.el.setHeight(size);
50818 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
50819 orientation: Roo.SplitBar.VERTICAL,
50820 getBox : function(){
50821 if(this.collapsed){
50822 return this.collapsedEl.getBox();
50824 var box = this.el.getBox();
50826 var sh = this.split.el.getHeight();
50833 updateBox : function(box){
50834 if(this.split && !this.collapsed){
50835 var sh = this.split.el.getHeight();
50838 this.split.el.setLeft(box.x);
50839 this.split.el.setTop(box.y-sh);
50840 this.split.el.setWidth(box.width);
50842 if(this.collapsed){
50843 this.updateBody(box.width, null);
50845 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50849 Roo.EastLayoutRegion = function(mgr, config){
50850 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
50852 this.split.placement = Roo.SplitBar.RIGHT;
50853 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50854 this.split.el.addClass("x-layout-split-h");
50856 var size = config.initialSize || config.width;
50857 if(typeof size != "undefined"){
50858 this.el.setWidth(size);
50861 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
50862 orientation: Roo.SplitBar.HORIZONTAL,
50863 getBox : function(){
50864 if(this.collapsed){
50865 return this.collapsedEl.getBox();
50867 var box = this.el.getBox();
50869 var sw = this.split.el.getWidth();
50876 updateBox : function(box){
50877 if(this.split && !this.collapsed){
50878 var sw = this.split.el.getWidth();
50880 this.split.el.setLeft(box.x);
50881 this.split.el.setTop(box.y);
50882 this.split.el.setHeight(box.height);
50885 if(this.collapsed){
50886 this.updateBody(null, box.height);
50888 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50892 Roo.WestLayoutRegion = function(mgr, config){
50893 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
50895 this.split.placement = Roo.SplitBar.LEFT;
50896 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50897 this.split.el.addClass("x-layout-split-h");
50899 var size = config.initialSize || config.width;
50900 if(typeof size != "undefined"){
50901 this.el.setWidth(size);
50904 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
50905 orientation: Roo.SplitBar.HORIZONTAL,
50906 getBox : function(){
50907 if(this.collapsed){
50908 return this.collapsedEl.getBox();
50910 var box = this.el.getBox();
50912 box.width += this.split.el.getWidth();
50917 updateBox : function(box){
50918 if(this.split && !this.collapsed){
50919 var sw = this.split.el.getWidth();
50921 this.split.el.setLeft(box.x+box.width);
50922 this.split.el.setTop(box.y);
50923 this.split.el.setHeight(box.height);
50925 if(this.collapsed){
50926 this.updateBody(null, box.height);
50928 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50933 * Ext JS Library 1.1.1
50934 * Copyright(c) 2006-2007, Ext JS, LLC.
50936 * Originally Released Under LGPL - original licence link has changed is not relivant.
50939 * <script type="text/javascript">
50944 * Private internal class for reading and applying state
50946 Roo.LayoutStateManager = function(layout){
50947 // default empty state
50956 Roo.LayoutStateManager.prototype = {
50957 init : function(layout, provider){
50958 this.provider = provider;
50959 var state = provider.get(layout.id+"-layout-state");
50961 var wasUpdating = layout.isUpdating();
50963 layout.beginUpdate();
50965 for(var key in state){
50966 if(typeof state[key] != "function"){
50967 var rstate = state[key];
50968 var r = layout.getRegion(key);
50971 r.resizeTo(rstate.size);
50973 if(rstate.collapsed == true){
50976 r.expand(null, true);
50982 layout.endUpdate();
50984 this.state = state;
50986 this.layout = layout;
50987 layout.on("regionresized", this.onRegionResized, this);
50988 layout.on("regioncollapsed", this.onRegionCollapsed, this);
50989 layout.on("regionexpanded", this.onRegionExpanded, this);
50992 storeState : function(){
50993 this.provider.set(this.layout.id+"-layout-state", this.state);
50996 onRegionResized : function(region, newSize){
50997 this.state[region.getPosition()].size = newSize;
51001 onRegionCollapsed : function(region){
51002 this.state[region.getPosition()].collapsed = true;
51006 onRegionExpanded : function(region){
51007 this.state[region.getPosition()].collapsed = false;
51012 * Ext JS Library 1.1.1
51013 * Copyright(c) 2006-2007, Ext JS, LLC.
51015 * Originally Released Under LGPL - original licence link has changed is not relivant.
51018 * <script type="text/javascript">
51021 * @class Roo.ContentPanel
51022 * @extends Roo.util.Observable
51023 * A basic ContentPanel element.
51024 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
51025 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
51026 * @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
51027 * @cfg {Boolean} closable True if the panel can be closed/removed
51028 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
51029 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
51030 * @cfg {Toolbar} toolbar A toolbar for this panel
51031 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
51032 * @cfg {String} title The title for this panel
51033 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
51034 * @cfg {String} url Calls {@link #setUrl} with this value
51035 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
51036 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
51037 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
51038 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
51041 * Create a new ContentPanel.
51042 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
51043 * @param {String/Object} config A string to set only the title or a config object
51044 * @param {String} content (optional) Set the HTML content for this panel
51045 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
51047 Roo.ContentPanel = function(el, config, content){
51051 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
51055 if (config && config.parentLayout) {
51056 el = config.parentLayout.el.createChild();
51059 if(el.autoCreate){ // xtype is available if this is called from factory
51063 this.el = Roo.get(el);
51064 if(!this.el && config && config.autoCreate){
51065 if(typeof config.autoCreate == "object"){
51066 if(!config.autoCreate.id){
51067 config.autoCreate.id = config.id||el;
51069 this.el = Roo.DomHelper.append(document.body,
51070 config.autoCreate, true);
51072 this.el = Roo.DomHelper.append(document.body,
51073 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
51076 this.closable = false;
51077 this.loaded = false;
51078 this.active = false;
51079 if(typeof config == "string"){
51080 this.title = config;
51082 Roo.apply(this, config);
51085 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
51086 this.wrapEl = this.el.wrap();
51087 this.toolbar.container = this.el.insertSibling(false, 'before');
51088 this.toolbar = new Roo.Toolbar(this.toolbar);
51091 // xtype created footer. - not sure if will work as we normally have to render first..
51092 if (this.footer && !this.footer.el && this.footer.xtype) {
51093 if (!this.wrapEl) {
51094 this.wrapEl = this.el.wrap();
51097 this.footer.container = this.wrapEl.createChild();
51099 this.footer = Roo.factory(this.footer, Roo);
51104 this.resizeEl = Roo.get(this.resizeEl, true);
51106 this.resizeEl = this.el;
51108 // handle view.xtype
51116 * Fires when this panel is activated.
51117 * @param {Roo.ContentPanel} this
51121 * @event deactivate
51122 * Fires when this panel is activated.
51123 * @param {Roo.ContentPanel} this
51125 "deactivate" : true,
51129 * Fires when this panel is resized if fitToFrame is true.
51130 * @param {Roo.ContentPanel} this
51131 * @param {Number} width The width after any component adjustments
51132 * @param {Number} height The height after any component adjustments
51138 * Fires when this tab is created
51139 * @param {Roo.ContentPanel} this
51150 if(this.autoScroll){
51151 this.resizeEl.setStyle("overflow", "auto");
51153 // fix randome scrolling
51154 this.el.on('scroll', function() {
51155 Roo.log('fix random scolling');
51156 this.scrollTo('top',0);
51159 content = content || this.content;
51161 this.setContent(content);
51163 if(config && config.url){
51164 this.setUrl(this.url, this.params, this.loadOnce);
51169 Roo.ContentPanel.superclass.constructor.call(this);
51171 if (this.view && typeof(this.view.xtype) != 'undefined') {
51172 this.view.el = this.el.appendChild(document.createElement("div"));
51173 this.view = Roo.factory(this.view);
51174 this.view.render && this.view.render(false, '');
51178 this.fireEvent('render', this);
51181 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51183 setRegion : function(region){
51184 this.region = region;
51186 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51188 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51193 * Returns the toolbar for this Panel if one was configured.
51194 * @return {Roo.Toolbar}
51196 getToolbar : function(){
51197 return this.toolbar;
51200 setActiveState : function(active){
51201 this.active = active;
51203 this.fireEvent("deactivate", this);
51205 this.fireEvent("activate", this);
51209 * Updates this panel's element
51210 * @param {String} content The new content
51211 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51213 setContent : function(content, loadScripts){
51214 this.el.update(content, loadScripts);
51217 ignoreResize : function(w, h){
51218 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51221 this.lastSize = {width: w, height: h};
51226 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51227 * @return {Roo.UpdateManager} The UpdateManager
51229 getUpdateManager : function(){
51230 return this.el.getUpdateManager();
51233 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51234 * @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:
51237 url: "your-url.php",
51238 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51239 callback: yourFunction,
51240 scope: yourObject, //(optional scope)
51243 text: "Loading...",
51248 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51249 * 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.
51250 * @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}
51251 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51252 * @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.
51253 * @return {Roo.ContentPanel} this
51256 var um = this.el.getUpdateManager();
51257 um.update.apply(um, arguments);
51263 * 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.
51264 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51265 * @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)
51266 * @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)
51267 * @return {Roo.UpdateManager} The UpdateManager
51269 setUrl : function(url, params, loadOnce){
51270 if(this.refreshDelegate){
51271 this.removeListener("activate", this.refreshDelegate);
51273 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51274 this.on("activate", this.refreshDelegate);
51275 return this.el.getUpdateManager();
51278 _handleRefresh : function(url, params, loadOnce){
51279 if(!loadOnce || !this.loaded){
51280 var updater = this.el.getUpdateManager();
51281 updater.update(url, params, this._setLoaded.createDelegate(this));
51285 _setLoaded : function(){
51286 this.loaded = true;
51290 * Returns this panel's id
51293 getId : function(){
51298 * Returns this panel's element - used by regiosn to add.
51299 * @return {Roo.Element}
51301 getEl : function(){
51302 return this.wrapEl || this.el;
51305 adjustForComponents : function(width, height)
51307 //Roo.log('adjustForComponents ');
51308 if(this.resizeEl != this.el){
51309 width -= this.el.getFrameWidth('lr');
51310 height -= this.el.getFrameWidth('tb');
51313 var te = this.toolbar.getEl();
51314 height -= te.getHeight();
51315 te.setWidth(width);
51318 var te = this.footer.getEl();
51319 Roo.log("footer:" + te.getHeight());
51321 height -= te.getHeight();
51322 te.setWidth(width);
51326 if(this.adjustments){
51327 width += this.adjustments[0];
51328 height += this.adjustments[1];
51330 return {"width": width, "height": height};
51333 setSize : function(width, height){
51334 if(this.fitToFrame && !this.ignoreResize(width, height)){
51335 if(this.fitContainer && this.resizeEl != this.el){
51336 this.el.setSize(width, height);
51338 var size = this.adjustForComponents(width, height);
51339 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51340 this.fireEvent('resize', this, size.width, size.height);
51345 * Returns this panel's title
51348 getTitle : function(){
51353 * Set this panel's title
51354 * @param {String} title
51356 setTitle : function(title){
51357 this.title = title;
51359 this.region.updatePanelTitle(this, title);
51364 * Returns true is this panel was configured to be closable
51365 * @return {Boolean}
51367 isClosable : function(){
51368 return this.closable;
51371 beforeSlide : function(){
51373 this.resizeEl.clip();
51376 afterSlide : function(){
51378 this.resizeEl.unclip();
51382 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51383 * Will fail silently if the {@link #setUrl} method has not been called.
51384 * This does not activate the panel, just updates its content.
51386 refresh : function(){
51387 if(this.refreshDelegate){
51388 this.loaded = false;
51389 this.refreshDelegate();
51394 * Destroys this panel
51396 destroy : function(){
51397 this.el.removeAllListeners();
51398 var tempEl = document.createElement("span");
51399 tempEl.appendChild(this.el.dom);
51400 tempEl.innerHTML = "";
51406 * form - if the content panel contains a form - this is a reference to it.
51407 * @type {Roo.form.Form}
51411 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51412 * This contains a reference to it.
51418 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51428 * @param {Object} cfg Xtype definition of item to add.
51431 addxtype : function(cfg) {
51433 if (cfg.xtype.match(/^Form$/)) {
51436 //if (this.footer) {
51437 // el = this.footer.container.insertSibling(false, 'before');
51439 el = this.el.createChild();
51442 this.form = new Roo.form.Form(cfg);
51445 if ( this.form.allItems.length) this.form.render(el.dom);
51448 // should only have one of theses..
51449 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51450 // views.. should not be just added - used named prop 'view''
51452 cfg.el = this.el.appendChild(document.createElement("div"));
51455 var ret = new Roo.factory(cfg);
51457 ret.render && ret.render(false, ''); // render blank..
51466 * @class Roo.GridPanel
51467 * @extends Roo.ContentPanel
51469 * Create a new GridPanel.
51470 * @param {Roo.grid.Grid} grid The grid for this panel
51471 * @param {String/Object} config A string to set only the panel's title, or a config object
51473 Roo.GridPanel = function(grid, config){
51476 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51477 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51479 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51481 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51484 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51486 // xtype created footer. - not sure if will work as we normally have to render first..
51487 if (this.footer && !this.footer.el && this.footer.xtype) {
51489 this.footer.container = this.grid.getView().getFooterPanel(true);
51490 this.footer.dataSource = this.grid.dataSource;
51491 this.footer = Roo.factory(this.footer, Roo);
51495 grid.monitorWindowResize = false; // turn off autosizing
51496 grid.autoHeight = false;
51497 grid.autoWidth = false;
51499 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51502 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51503 getId : function(){
51504 return this.grid.id;
51508 * Returns the grid for this panel
51509 * @return {Roo.grid.Grid}
51511 getGrid : function(){
51515 setSize : function(width, height){
51516 if(!this.ignoreResize(width, height)){
51517 var grid = this.grid;
51518 var size = this.adjustForComponents(width, height);
51519 grid.getGridEl().setSize(size.width, size.height);
51524 beforeSlide : function(){
51525 this.grid.getView().scroller.clip();
51528 afterSlide : function(){
51529 this.grid.getView().scroller.unclip();
51532 destroy : function(){
51533 this.grid.destroy();
51535 Roo.GridPanel.superclass.destroy.call(this);
51541 * @class Roo.NestedLayoutPanel
51542 * @extends Roo.ContentPanel
51544 * Create a new NestedLayoutPanel.
51547 * @param {Roo.BorderLayout} layout The layout for this panel
51548 * @param {String/Object} config A string to set only the title or a config object
51550 Roo.NestedLayoutPanel = function(layout, config)
51552 // construct with only one argument..
51553 /* FIXME - implement nicer consturctors
51554 if (layout.layout) {
51556 layout = config.layout;
51557 delete config.layout;
51559 if (layout.xtype && !layout.getEl) {
51560 // then layout needs constructing..
51561 layout = Roo.factory(layout, Roo);
51566 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51568 layout.monitorWindowResize = false; // turn off autosizing
51569 this.layout = layout;
51570 this.layout.getEl().addClass("x-layout-nested-layout");
51577 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51579 setSize : function(width, height){
51580 if(!this.ignoreResize(width, height)){
51581 var size = this.adjustForComponents(width, height);
51582 var el = this.layout.getEl();
51583 el.setSize(size.width, size.height);
51584 var touch = el.dom.offsetWidth;
51585 this.layout.layout();
51586 // ie requires a double layout on the first pass
51587 if(Roo.isIE && !this.initialized){
51588 this.initialized = true;
51589 this.layout.layout();
51594 // activate all subpanels if not currently active..
51596 setActiveState : function(active){
51597 this.active = active;
51599 this.fireEvent("deactivate", this);
51603 this.fireEvent("activate", this);
51604 // not sure if this should happen before or after..
51605 if (!this.layout) {
51606 return; // should not happen..
51609 for (var r in this.layout.regions) {
51610 reg = this.layout.getRegion(r);
51611 if (reg.getActivePanel()) {
51612 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51613 reg.setActivePanel(reg.getActivePanel());
51616 if (!reg.panels.length) {
51619 reg.showPanel(reg.getPanel(0));
51628 * Returns the nested BorderLayout for this panel
51629 * @return {Roo.BorderLayout}
51631 getLayout : function(){
51632 return this.layout;
51636 * Adds a xtype elements to the layout of the nested panel
51640 xtype : 'ContentPanel',
51647 xtype : 'NestedLayoutPanel',
51653 items : [ ... list of content panels or nested layout panels.. ]
51657 * @param {Object} cfg Xtype definition of item to add.
51659 addxtype : function(cfg) {
51660 return this.layout.addxtype(cfg);
51665 Roo.ScrollPanel = function(el, config, content){
51666 config = config || {};
51667 config.fitToFrame = true;
51668 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
51670 this.el.dom.style.overflow = "hidden";
51671 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
51672 this.el.removeClass("x-layout-inactive-content");
51673 this.el.on("mousewheel", this.onWheel, this);
51675 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
51676 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
51677 up.unselectable(); down.unselectable();
51678 up.on("click", this.scrollUp, this);
51679 down.on("click", this.scrollDown, this);
51680 up.addClassOnOver("x-scroller-btn-over");
51681 down.addClassOnOver("x-scroller-btn-over");
51682 up.addClassOnClick("x-scroller-btn-click");
51683 down.addClassOnClick("x-scroller-btn-click");
51684 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
51686 this.resizeEl = this.el;
51687 this.el = wrap; this.up = up; this.down = down;
51690 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
51692 wheelIncrement : 5,
51693 scrollUp : function(){
51694 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
51697 scrollDown : function(){
51698 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
51701 afterScroll : function(){
51702 var el = this.resizeEl;
51703 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
51704 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51705 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51708 setSize : function(){
51709 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
51710 this.afterScroll();
51713 onWheel : function(e){
51714 var d = e.getWheelDelta();
51715 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
51716 this.afterScroll();
51720 setContent : function(content, loadScripts){
51721 this.resizeEl.update(content, loadScripts);
51735 * @class Roo.TreePanel
51736 * @extends Roo.ContentPanel
51738 * Create a new TreePanel. - defaults to fit/scoll contents.
51739 * @param {String/Object} config A string to set only the panel's title, or a config object
51740 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
51742 Roo.TreePanel = function(config){
51743 var el = config.el;
51744 var tree = config.tree;
51745 delete config.tree;
51746 delete config.el; // hopefull!
51748 // wrapper for IE7 strict & safari scroll issue
51750 var treeEl = el.createChild();
51751 config.resizeEl = treeEl;
51755 Roo.TreePanel.superclass.constructor.call(this, el, config);
51758 this.tree = new Roo.tree.TreePanel(treeEl , tree);
51759 //console.log(tree);
51760 this.on('activate', function()
51762 if (this.tree.rendered) {
51765 //console.log('render tree');
51766 this.tree.render();
51768 // this should not be needed.. - it's actually the 'el' that resizes?
51769 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
51771 //this.on('resize', function (cp, w, h) {
51772 // this.tree.innerCt.setWidth(w);
51773 // this.tree.innerCt.setHeight(h);
51774 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
51781 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
51798 * Ext JS Library 1.1.1
51799 * Copyright(c) 2006-2007, Ext JS, LLC.
51801 * Originally Released Under LGPL - original licence link has changed is not relivant.
51804 * <script type="text/javascript">
51809 * @class Roo.ReaderLayout
51810 * @extends Roo.BorderLayout
51811 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
51812 * center region containing two nested regions (a top one for a list view and one for item preview below),
51813 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
51814 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
51815 * expedites the setup of the overall layout and regions for this common application style.
51818 var reader = new Roo.ReaderLayout();
51819 var CP = Roo.ContentPanel; // shortcut for adding
51821 reader.beginUpdate();
51822 reader.add("north", new CP("north", "North"));
51823 reader.add("west", new CP("west", {title: "West"}));
51824 reader.add("east", new CP("east", {title: "East"}));
51826 reader.regions.listView.add(new CP("listView", "List"));
51827 reader.regions.preview.add(new CP("preview", "Preview"));
51828 reader.endUpdate();
51831 * Create a new ReaderLayout
51832 * @param {Object} config Configuration options
51833 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
51834 * document.body if omitted)
51836 Roo.ReaderLayout = function(config, renderTo){
51837 var c = config || {size:{}};
51838 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
51839 north: c.north !== false ? Roo.apply({
51843 }, c.north) : false,
51844 west: c.west !== false ? Roo.apply({
51852 margins:{left:5,right:0,bottom:5,top:5},
51853 cmargins:{left:5,right:5,bottom:5,top:5}
51854 }, c.west) : false,
51855 east: c.east !== false ? Roo.apply({
51863 margins:{left:0,right:5,bottom:5,top:5},
51864 cmargins:{left:5,right:5,bottom:5,top:5}
51865 }, c.east) : false,
51866 center: Roo.apply({
51867 tabPosition: 'top',
51871 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
51875 this.el.addClass('x-reader');
51877 this.beginUpdate();
51879 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
51880 south: c.preview !== false ? Roo.apply({
51887 cmargins:{top:5,left:0, right:0, bottom:0}
51888 }, c.preview) : false,
51889 center: Roo.apply({
51895 this.add('center', new Roo.NestedLayoutPanel(inner,
51896 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
51900 this.regions.preview = inner.getRegion('south');
51901 this.regions.listView = inner.getRegion('center');
51904 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
51906 * Ext JS Library 1.1.1
51907 * Copyright(c) 2006-2007, Ext JS, LLC.
51909 * Originally Released Under LGPL - original licence link has changed is not relivant.
51912 * <script type="text/javascript">
51916 * @class Roo.grid.Grid
51917 * @extends Roo.util.Observable
51918 * This class represents the primary interface of a component based grid control.
51919 * <br><br>Usage:<pre><code>
51920 var grid = new Roo.grid.Grid("my-container-id", {
51923 selModel: mySelectionModel,
51924 autoSizeColumns: true,
51925 monitorWindowResize: false,
51926 trackMouseOver: true
51931 * <b>Common Problems:</b><br/>
51932 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
51933 * element will correct this<br/>
51934 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
51935 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
51936 * are unpredictable.<br/>
51937 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
51938 * grid to calculate dimensions/offsets.<br/>
51940 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51941 * The container MUST have some type of size defined for the grid to fill. The container will be
51942 * automatically set to position relative if it isn't already.
51943 * @param {Object} config A config object that sets properties on this grid.
51945 Roo.grid.Grid = function(container, config){
51946 // initialize the container
51947 this.container = Roo.get(container);
51948 this.container.update("");
51949 this.container.setStyle("overflow", "hidden");
51950 this.container.addClass('x-grid-container');
51952 this.id = this.container.id;
51954 Roo.apply(this, config);
51955 // check and correct shorthanded configs
51957 this.dataSource = this.ds;
51961 this.colModel = this.cm;
51965 this.selModel = this.sm;
51969 if (this.selModel) {
51970 this.selModel = Roo.factory(this.selModel, Roo.grid);
51971 this.sm = this.selModel;
51972 this.sm.xmodule = this.xmodule || false;
51974 if (typeof(this.colModel.config) == 'undefined') {
51975 this.colModel = new Roo.grid.ColumnModel(this.colModel);
51976 this.cm = this.colModel;
51977 this.cm.xmodule = this.xmodule || false;
51979 if (this.dataSource) {
51980 this.dataSource= Roo.factory(this.dataSource, Roo.data);
51981 this.ds = this.dataSource;
51982 this.ds.xmodule = this.xmodule || false;
51989 this.container.setWidth(this.width);
51993 this.container.setHeight(this.height);
52000 * The raw click event for the entire grid.
52001 * @param {Roo.EventObject} e
52006 * The raw dblclick event for the entire grid.
52007 * @param {Roo.EventObject} e
52011 * @event contextmenu
52012 * The raw contextmenu event for the entire grid.
52013 * @param {Roo.EventObject} e
52015 "contextmenu" : true,
52018 * The raw mousedown event for the entire grid.
52019 * @param {Roo.EventObject} e
52021 "mousedown" : true,
52024 * The raw mouseup event for the entire grid.
52025 * @param {Roo.EventObject} e
52030 * The raw mouseover event for the entire grid.
52031 * @param {Roo.EventObject} e
52033 "mouseover" : true,
52036 * The raw mouseout event for the entire grid.
52037 * @param {Roo.EventObject} e
52042 * The raw keypress event for the entire grid.
52043 * @param {Roo.EventObject} e
52048 * The raw keydown event for the entire grid.
52049 * @param {Roo.EventObject} e
52057 * Fires when a cell is clicked
52058 * @param {Grid} this
52059 * @param {Number} rowIndex
52060 * @param {Number} columnIndex
52061 * @param {Roo.EventObject} e
52063 "cellclick" : true,
52065 * @event celldblclick
52066 * Fires when a cell is double clicked
52067 * @param {Grid} this
52068 * @param {Number} rowIndex
52069 * @param {Number} columnIndex
52070 * @param {Roo.EventObject} e
52072 "celldblclick" : true,
52075 * Fires when a row is clicked
52076 * @param {Grid} this
52077 * @param {Number} rowIndex
52078 * @param {Roo.EventObject} e
52082 * @event rowdblclick
52083 * Fires when a row is double clicked
52084 * @param {Grid} this
52085 * @param {Number} rowIndex
52086 * @param {Roo.EventObject} e
52088 "rowdblclick" : true,
52090 * @event headerclick
52091 * Fires when a header is clicked
52092 * @param {Grid} this
52093 * @param {Number} columnIndex
52094 * @param {Roo.EventObject} e
52096 "headerclick" : true,
52098 * @event headerdblclick
52099 * Fires when a header cell is double clicked
52100 * @param {Grid} this
52101 * @param {Number} columnIndex
52102 * @param {Roo.EventObject} e
52104 "headerdblclick" : true,
52106 * @event rowcontextmenu
52107 * Fires when a row is right clicked
52108 * @param {Grid} this
52109 * @param {Number} rowIndex
52110 * @param {Roo.EventObject} e
52112 "rowcontextmenu" : true,
52114 * @event cellcontextmenu
52115 * Fires when a cell is right clicked
52116 * @param {Grid} this
52117 * @param {Number} rowIndex
52118 * @param {Number} cellIndex
52119 * @param {Roo.EventObject} e
52121 "cellcontextmenu" : true,
52123 * @event headercontextmenu
52124 * Fires when a header is right clicked
52125 * @param {Grid} this
52126 * @param {Number} columnIndex
52127 * @param {Roo.EventObject} e
52129 "headercontextmenu" : true,
52131 * @event bodyscroll
52132 * Fires when the body element is scrolled
52133 * @param {Number} scrollLeft
52134 * @param {Number} scrollTop
52136 "bodyscroll" : true,
52138 * @event columnresize
52139 * Fires when the user resizes a column
52140 * @param {Number} columnIndex
52141 * @param {Number} newSize
52143 "columnresize" : true,
52145 * @event columnmove
52146 * Fires when the user moves a column
52147 * @param {Number} oldIndex
52148 * @param {Number} newIndex
52150 "columnmove" : true,
52153 * Fires when row(s) start being dragged
52154 * @param {Grid} this
52155 * @param {Roo.GridDD} dd The drag drop object
52156 * @param {event} e The raw browser event
52158 "startdrag" : true,
52161 * Fires when a drag operation is complete
52162 * @param {Grid} this
52163 * @param {Roo.GridDD} dd The drag drop object
52164 * @param {event} e The raw browser event
52169 * Fires when dragged row(s) are dropped on a valid DD target
52170 * @param {Grid} this
52171 * @param {Roo.GridDD} dd The drag drop object
52172 * @param {String} targetId The target drag drop object
52173 * @param {event} e The raw browser event
52178 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52179 * @param {Grid} this
52180 * @param {Roo.GridDD} dd The drag drop object
52181 * @param {String} targetId The target drag drop object
52182 * @param {event} e The raw browser event
52187 * Fires when the dragged row(s) first cross another DD target while being dragged
52188 * @param {Grid} this
52189 * @param {Roo.GridDD} dd The drag drop object
52190 * @param {String} targetId The target drag drop object
52191 * @param {event} e The raw browser event
52193 "dragenter" : true,
52196 * Fires when the dragged row(s) leave another DD target while being dragged
52197 * @param {Grid} this
52198 * @param {Roo.GridDD} dd The drag drop object
52199 * @param {String} targetId The target drag drop object
52200 * @param {event} e The raw browser event
52205 * Fires when a row is rendered, so you can change add a style to it.
52206 * @param {GridView} gridview The grid view
52207 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52213 * Fires when the grid is rendered
52214 * @param {Grid} grid
52219 Roo.grid.Grid.superclass.constructor.call(this);
52221 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52224 * @cfg {String} ddGroup - drag drop group.
52228 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52230 minColumnWidth : 25,
52233 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52234 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52235 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52237 autoSizeColumns : false,
52240 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52242 autoSizeHeaders : true,
52245 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52247 monitorWindowResize : true,
52250 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52251 * rows measured to get a columns size. Default is 0 (all rows).
52253 maxRowsToMeasure : 0,
52256 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52258 trackMouseOver : true,
52261 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52265 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52267 enableDragDrop : false,
52270 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52272 enableColumnMove : true,
52275 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52277 enableColumnHide : true,
52280 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52282 enableRowHeightSync : false,
52285 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52290 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52292 autoHeight : false,
52295 * @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.
52297 autoExpandColumn : false,
52300 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52303 autoExpandMin : 50,
52306 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52308 autoExpandMax : 1000,
52311 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52316 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52320 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52330 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52331 * of a fixed width. Default is false.
52334 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52337 * Called once after all setup has been completed and the grid is ready to be rendered.
52338 * @return {Roo.grid.Grid} this
52340 render : function()
52342 var c = this.container;
52343 // try to detect autoHeight/width mode
52344 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52345 this.autoHeight = true;
52347 var view = this.getView();
52350 c.on("click", this.onClick, this);
52351 c.on("dblclick", this.onDblClick, this);
52352 c.on("contextmenu", this.onContextMenu, this);
52353 c.on("keydown", this.onKeyDown, this);
52355 c.on("touchstart", this.onTouchStart, this);
52358 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52360 this.getSelectionModel().init(this);
52365 this.loadMask = new Roo.LoadMask(this.container,
52366 Roo.apply({store:this.dataSource}, this.loadMask));
52370 if (this.toolbar && this.toolbar.xtype) {
52371 this.toolbar.container = this.getView().getHeaderPanel(true);
52372 this.toolbar = new Roo.Toolbar(this.toolbar);
52374 if (this.footer && this.footer.xtype) {
52375 this.footer.dataSource = this.getDataSource();
52376 this.footer.container = this.getView().getFooterPanel(true);
52377 this.footer = Roo.factory(this.footer, Roo);
52379 if (this.dropTarget && this.dropTarget.xtype) {
52380 delete this.dropTarget.xtype;
52381 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52385 this.rendered = true;
52386 this.fireEvent('render', this);
52391 * Reconfigures the grid to use a different Store and Column Model.
52392 * The View will be bound to the new objects and refreshed.
52393 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52394 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52396 reconfigure : function(dataSource, colModel){
52398 this.loadMask.destroy();
52399 this.loadMask = new Roo.LoadMask(this.container,
52400 Roo.apply({store:dataSource}, this.loadMask));
52402 this.view.bind(dataSource, colModel);
52403 this.dataSource = dataSource;
52404 this.colModel = colModel;
52405 this.view.refresh(true);
52409 onKeyDown : function(e){
52410 this.fireEvent("keydown", e);
52414 * Destroy this grid.
52415 * @param {Boolean} removeEl True to remove the element
52417 destroy : function(removeEl, keepListeners){
52419 this.loadMask.destroy();
52421 var c = this.container;
52422 c.removeAllListeners();
52423 this.view.destroy();
52424 this.colModel.purgeListeners();
52425 if(!keepListeners){
52426 this.purgeListeners();
52429 if(removeEl === true){
52435 processEvent : function(name, e){
52436 // does this fire select???
52437 Roo.log('grid:processEvent ' + name);
52439 if (name != 'touchstart' ) {
52440 this.fireEvent(name, e);
52443 var t = e.getTarget();
52445 var header = v.findHeaderIndex(t);
52446 if(header !== false){
52447 var ename = name == 'touchstart' ? 'click' : name;
52449 this.fireEvent("header" + ename, this, header, e);
52451 var row = v.findRowIndex(t);
52452 var cell = v.findCellIndex(t);
52453 if (name == 'touchstart') {
52454 // first touch is always a click.
52455 // hopefull this happens after selection is updated.?
52458 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52459 var cs = this.selModel.getSelectedCell();
52460 if (row == cs[0] && cell == cs[1]){
52464 if (typeof(this.selModel.getSelections) != 'undefined') {
52465 var cs = this.selModel.getSelections();
52466 var ds = this.dataSource;
52467 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52478 this.fireEvent("row" + name, this, row, e);
52479 if(cell !== false){
52480 this.fireEvent("cell" + name, this, row, cell, e);
52487 onClick : function(e){
52488 this.processEvent("click", e);
52491 onTouchStart : function(e){
52492 this.processEvent("touchstart", e);
52496 onContextMenu : function(e, t){
52497 this.processEvent("contextmenu", e);
52501 onDblClick : function(e){
52502 this.processEvent("dblclick", e);
52506 walkCells : function(row, col, step, fn, scope){
52507 var cm = this.colModel, clen = cm.getColumnCount();
52508 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52520 if(fn.call(scope || this, row, col, cm) === true){
52538 if(fn.call(scope || this, row, col, cm) === true){
52550 getSelections : function(){
52551 return this.selModel.getSelections();
52555 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52556 * but if manual update is required this method will initiate it.
52558 autoSize : function(){
52560 this.view.layout();
52561 if(this.view.adjustForScroll){
52562 this.view.adjustForScroll();
52568 * Returns the grid's underlying element.
52569 * @return {Element} The element
52571 getGridEl : function(){
52572 return this.container;
52575 // private for compatibility, overridden by editor grid
52576 stopEditing : function(){},
52579 * Returns the grid's SelectionModel.
52580 * @return {SelectionModel}
52582 getSelectionModel : function(){
52583 if(!this.selModel){
52584 this.selModel = new Roo.grid.RowSelectionModel();
52586 return this.selModel;
52590 * Returns the grid's DataSource.
52591 * @return {DataSource}
52593 getDataSource : function(){
52594 return this.dataSource;
52598 * Returns the grid's ColumnModel.
52599 * @return {ColumnModel}
52601 getColumnModel : function(){
52602 return this.colModel;
52606 * Returns the grid's GridView object.
52607 * @return {GridView}
52609 getView : function(){
52611 this.view = new Roo.grid.GridView(this.viewConfig);
52616 * Called to get grid's drag proxy text, by default returns this.ddText.
52619 getDragDropText : function(){
52620 var count = this.selModel.getCount();
52621 return String.format(this.ddText, count, count == 1 ? '' : 's');
52625 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
52626 * %0 is replaced with the number of selected rows.
52629 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
52631 * Ext JS Library 1.1.1
52632 * Copyright(c) 2006-2007, Ext JS, LLC.
52634 * Originally Released Under LGPL - original licence link has changed is not relivant.
52637 * <script type="text/javascript">
52640 Roo.grid.AbstractGridView = function(){
52644 "beforerowremoved" : true,
52645 "beforerowsinserted" : true,
52646 "beforerefresh" : true,
52647 "rowremoved" : true,
52648 "rowsinserted" : true,
52649 "rowupdated" : true,
52652 Roo.grid.AbstractGridView.superclass.constructor.call(this);
52655 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
52656 rowClass : "x-grid-row",
52657 cellClass : "x-grid-cell",
52658 tdClass : "x-grid-td",
52659 hdClass : "x-grid-hd",
52660 splitClass : "x-grid-hd-split",
52662 init: function(grid){
52664 var cid = this.grid.getGridEl().id;
52665 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
52666 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
52667 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
52668 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
52671 getColumnRenderers : function(){
52672 var renderers = [];
52673 var cm = this.grid.colModel;
52674 var colCount = cm.getColumnCount();
52675 for(var i = 0; i < colCount; i++){
52676 renderers[i] = cm.getRenderer(i);
52681 getColumnIds : function(){
52683 var cm = this.grid.colModel;
52684 var colCount = cm.getColumnCount();
52685 for(var i = 0; i < colCount; i++){
52686 ids[i] = cm.getColumnId(i);
52691 getDataIndexes : function(){
52692 if(!this.indexMap){
52693 this.indexMap = this.buildIndexMap();
52695 return this.indexMap.colToData;
52698 getColumnIndexByDataIndex : function(dataIndex){
52699 if(!this.indexMap){
52700 this.indexMap = this.buildIndexMap();
52702 return this.indexMap.dataToCol[dataIndex];
52706 * Set a css style for a column dynamically.
52707 * @param {Number} colIndex The index of the column
52708 * @param {String} name The css property name
52709 * @param {String} value The css value
52711 setCSSStyle : function(colIndex, name, value){
52712 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
52713 Roo.util.CSS.updateRule(selector, name, value);
52716 generateRules : function(cm){
52717 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
52718 Roo.util.CSS.removeStyleSheet(rulesId);
52719 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52720 var cid = cm.getColumnId(i);
52721 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
52722 this.tdSelector, cid, " {\n}\n",
52723 this.hdSelector, cid, " {\n}\n",
52724 this.splitSelector, cid, " {\n}\n");
52726 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52730 * Ext JS Library 1.1.1
52731 * Copyright(c) 2006-2007, Ext JS, LLC.
52733 * Originally Released Under LGPL - original licence link has changed is not relivant.
52736 * <script type="text/javascript">
52740 // This is a support class used internally by the Grid components
52741 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
52743 this.view = grid.getView();
52744 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52745 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
52747 this.setHandleElId(Roo.id(hd));
52748 this.setOuterHandleElId(Roo.id(hd2));
52750 this.scroll = false;
52752 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
52754 getDragData : function(e){
52755 var t = Roo.lib.Event.getTarget(e);
52756 var h = this.view.findHeaderCell(t);
52758 return {ddel: h.firstChild, header:h};
52763 onInitDrag : function(e){
52764 this.view.headersDisabled = true;
52765 var clone = this.dragData.ddel.cloneNode(true);
52766 clone.id = Roo.id();
52767 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
52768 this.proxy.update(clone);
52772 afterValidDrop : function(){
52774 setTimeout(function(){
52775 v.headersDisabled = false;
52779 afterInvalidDrop : function(){
52781 setTimeout(function(){
52782 v.headersDisabled = false;
52788 * Ext JS Library 1.1.1
52789 * Copyright(c) 2006-2007, Ext JS, LLC.
52791 * Originally Released Under LGPL - original licence link has changed is not relivant.
52794 * <script type="text/javascript">
52797 // This is a support class used internally by the Grid components
52798 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
52800 this.view = grid.getView();
52801 // split the proxies so they don't interfere with mouse events
52802 this.proxyTop = Roo.DomHelper.append(document.body, {
52803 cls:"col-move-top", html:" "
52805 this.proxyBottom = Roo.DomHelper.append(document.body, {
52806 cls:"col-move-bottom", html:" "
52808 this.proxyTop.hide = this.proxyBottom.hide = function(){
52809 this.setLeftTop(-100,-100);
52810 this.setStyle("visibility", "hidden");
52812 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52813 // temporarily disabled
52814 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
52815 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
52817 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
52818 proxyOffsets : [-4, -9],
52819 fly: Roo.Element.fly,
52821 getTargetFromEvent : function(e){
52822 var t = Roo.lib.Event.getTarget(e);
52823 var cindex = this.view.findCellIndex(t);
52824 if(cindex !== false){
52825 return this.view.getHeaderCell(cindex);
52830 nextVisible : function(h){
52831 var v = this.view, cm = this.grid.colModel;
52834 if(!cm.isHidden(v.getCellIndex(h))){
52842 prevVisible : function(h){
52843 var v = this.view, cm = this.grid.colModel;
52846 if(!cm.isHidden(v.getCellIndex(h))){
52854 positionIndicator : function(h, n, e){
52855 var x = Roo.lib.Event.getPageX(e);
52856 var r = Roo.lib.Dom.getRegion(n.firstChild);
52857 var px, pt, py = r.top + this.proxyOffsets[1];
52858 if((r.right - x) <= (r.right-r.left)/2){
52859 px = r.right+this.view.borderWidth;
52865 var oldIndex = this.view.getCellIndex(h);
52866 var newIndex = this.view.getCellIndex(n);
52868 if(this.grid.colModel.isFixed(newIndex)){
52872 var locked = this.grid.colModel.isLocked(newIndex);
52877 if(oldIndex < newIndex){
52880 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
52883 px += this.proxyOffsets[0];
52884 this.proxyTop.setLeftTop(px, py);
52885 this.proxyTop.show();
52886 if(!this.bottomOffset){
52887 this.bottomOffset = this.view.mainHd.getHeight();
52889 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
52890 this.proxyBottom.show();
52894 onNodeEnter : function(n, dd, e, data){
52895 if(data.header != n){
52896 this.positionIndicator(data.header, n, e);
52900 onNodeOver : function(n, dd, e, data){
52901 var result = false;
52902 if(data.header != n){
52903 result = this.positionIndicator(data.header, n, e);
52906 this.proxyTop.hide();
52907 this.proxyBottom.hide();
52909 return result ? this.dropAllowed : this.dropNotAllowed;
52912 onNodeOut : function(n, dd, e, data){
52913 this.proxyTop.hide();
52914 this.proxyBottom.hide();
52917 onNodeDrop : function(n, dd, e, data){
52918 var h = data.header;
52920 var cm = this.grid.colModel;
52921 var x = Roo.lib.Event.getPageX(e);
52922 var r = Roo.lib.Dom.getRegion(n.firstChild);
52923 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
52924 var oldIndex = this.view.getCellIndex(h);
52925 var newIndex = this.view.getCellIndex(n);
52926 var locked = cm.isLocked(newIndex);
52930 if(oldIndex < newIndex){
52933 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
52936 cm.setLocked(oldIndex, locked, true);
52937 cm.moveColumn(oldIndex, newIndex);
52938 this.grid.fireEvent("columnmove", oldIndex, newIndex);
52946 * Ext JS Library 1.1.1
52947 * Copyright(c) 2006-2007, Ext JS, LLC.
52949 * Originally Released Under LGPL - original licence link has changed is not relivant.
52952 * <script type="text/javascript">
52956 * @class Roo.grid.GridView
52957 * @extends Roo.util.Observable
52960 * @param {Object} config
52962 Roo.grid.GridView = function(config){
52963 Roo.grid.GridView.superclass.constructor.call(this);
52966 Roo.apply(this, config);
52969 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
52971 unselectable : 'unselectable="on"',
52972 unselectableCls : 'x-unselectable',
52975 rowClass : "x-grid-row",
52977 cellClass : "x-grid-col",
52979 tdClass : "x-grid-td",
52981 hdClass : "x-grid-hd",
52983 splitClass : "x-grid-split",
52985 sortClasses : ["sort-asc", "sort-desc"],
52987 enableMoveAnim : false,
52991 dh : Roo.DomHelper,
52993 fly : Roo.Element.fly,
52995 css : Roo.util.CSS,
53001 scrollIncrement : 22,
53003 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
53005 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
53007 bind : function(ds, cm){
53009 this.ds.un("load", this.onLoad, this);
53010 this.ds.un("datachanged", this.onDataChange, this);
53011 this.ds.un("add", this.onAdd, this);
53012 this.ds.un("remove", this.onRemove, this);
53013 this.ds.un("update", this.onUpdate, this);
53014 this.ds.un("clear", this.onClear, this);
53017 ds.on("load", this.onLoad, this);
53018 ds.on("datachanged", this.onDataChange, this);
53019 ds.on("add", this.onAdd, this);
53020 ds.on("remove", this.onRemove, this);
53021 ds.on("update", this.onUpdate, this);
53022 ds.on("clear", this.onClear, this);
53027 this.cm.un("widthchange", this.onColWidthChange, this);
53028 this.cm.un("headerchange", this.onHeaderChange, this);
53029 this.cm.un("hiddenchange", this.onHiddenChange, this);
53030 this.cm.un("columnmoved", this.onColumnMove, this);
53031 this.cm.un("columnlockchange", this.onColumnLock, this);
53034 this.generateRules(cm);
53035 cm.on("widthchange", this.onColWidthChange, this);
53036 cm.on("headerchange", this.onHeaderChange, this);
53037 cm.on("hiddenchange", this.onHiddenChange, this);
53038 cm.on("columnmoved", this.onColumnMove, this);
53039 cm.on("columnlockchange", this.onColumnLock, this);
53044 init: function(grid){
53045 Roo.grid.GridView.superclass.init.call(this, grid);
53047 this.bind(grid.dataSource, grid.colModel);
53049 grid.on("headerclick", this.handleHeaderClick, this);
53051 if(grid.trackMouseOver){
53052 grid.on("mouseover", this.onRowOver, this);
53053 grid.on("mouseout", this.onRowOut, this);
53055 grid.cancelTextSelection = function(){};
53056 this.gridId = grid.id;
53058 var tpls = this.templates || {};
53061 tpls.master = new Roo.Template(
53062 '<div class="x-grid" hidefocus="true">',
53063 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
53064 '<div class="x-grid-topbar"></div>',
53065 '<div class="x-grid-scroller"><div></div></div>',
53066 '<div class="x-grid-locked">',
53067 '<div class="x-grid-header">{lockedHeader}</div>',
53068 '<div class="x-grid-body">{lockedBody}</div>',
53070 '<div class="x-grid-viewport">',
53071 '<div class="x-grid-header">{header}</div>',
53072 '<div class="x-grid-body">{body}</div>',
53074 '<div class="x-grid-bottombar"></div>',
53076 '<div class="x-grid-resize-proxy"> </div>',
53079 tpls.master.disableformats = true;
53083 tpls.header = new Roo.Template(
53084 '<table border="0" cellspacing="0" cellpadding="0">',
53085 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
53088 tpls.header.disableformats = true;
53090 tpls.header.compile();
53093 tpls.hcell = new Roo.Template(
53094 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
53095 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
53098 tpls.hcell.disableFormats = true;
53100 tpls.hcell.compile();
53103 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
53104 this.unselectableCls + '" ' + this.unselectable +'> </div>');
53105 tpls.hsplit.disableFormats = true;
53107 tpls.hsplit.compile();
53110 tpls.body = new Roo.Template(
53111 '<table border="0" cellspacing="0" cellpadding="0">',
53112 "<tbody>{rows}</tbody>",
53115 tpls.body.disableFormats = true;
53117 tpls.body.compile();
53120 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
53121 tpls.row.disableFormats = true;
53123 tpls.row.compile();
53126 tpls.cell = new Roo.Template(
53127 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
53128 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
53129 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
53132 tpls.cell.disableFormats = true;
53134 tpls.cell.compile();
53136 this.templates = tpls;
53139 // remap these for backwards compat
53140 onColWidthChange : function(){
53141 this.updateColumns.apply(this, arguments);
53143 onHeaderChange : function(){
53144 this.updateHeaders.apply(this, arguments);
53146 onHiddenChange : function(){
53147 this.handleHiddenChange.apply(this, arguments);
53149 onColumnMove : function(){
53150 this.handleColumnMove.apply(this, arguments);
53152 onColumnLock : function(){
53153 this.handleLockChange.apply(this, arguments);
53156 onDataChange : function(){
53158 this.updateHeaderSortState();
53161 onClear : function(){
53165 onUpdate : function(ds, record){
53166 this.refreshRow(record);
53169 refreshRow : function(record){
53170 var ds = this.ds, index;
53171 if(typeof record == 'number'){
53173 record = ds.getAt(index);
53175 index = ds.indexOf(record);
53177 this.insertRows(ds, index, index, true);
53178 this.onRemove(ds, record, index+1, true);
53179 this.syncRowHeights(index, index);
53181 this.fireEvent("rowupdated", this, index, record);
53184 onAdd : function(ds, records, index){
53185 this.insertRows(ds, index, index + (records.length-1));
53188 onRemove : function(ds, record, index, isUpdate){
53189 if(isUpdate !== true){
53190 this.fireEvent("beforerowremoved", this, index, record);
53192 var bt = this.getBodyTable(), lt = this.getLockedTable();
53193 if(bt.rows[index]){
53194 bt.firstChild.removeChild(bt.rows[index]);
53196 if(lt.rows[index]){
53197 lt.firstChild.removeChild(lt.rows[index]);
53199 if(isUpdate !== true){
53200 this.stripeRows(index);
53201 this.syncRowHeights(index, index);
53203 this.fireEvent("rowremoved", this, index, record);
53207 onLoad : function(){
53208 this.scrollToTop();
53212 * Scrolls the grid to the top
53214 scrollToTop : function(){
53216 this.scroller.dom.scrollTop = 0;
53222 * Gets a panel in the header of the grid that can be used for toolbars etc.
53223 * After modifying the contents of this panel a call to grid.autoSize() may be
53224 * required to register any changes in size.
53225 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53226 * @return Roo.Element
53228 getHeaderPanel : function(doShow){
53230 this.headerPanel.show();
53232 return this.headerPanel;
53236 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53237 * After modifying the contents of this panel a call to grid.autoSize() may be
53238 * required to register any changes in size.
53239 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53240 * @return Roo.Element
53242 getFooterPanel : function(doShow){
53244 this.footerPanel.show();
53246 return this.footerPanel;
53249 initElements : function(){
53250 var E = Roo.Element;
53251 var el = this.grid.getGridEl().dom.firstChild;
53252 var cs = el.childNodes;
53254 this.el = new E(el);
53256 this.focusEl = new E(el.firstChild);
53257 this.focusEl.swallowEvent("click", true);
53259 this.headerPanel = new E(cs[1]);
53260 this.headerPanel.enableDisplayMode("block");
53262 this.scroller = new E(cs[2]);
53263 this.scrollSizer = new E(this.scroller.dom.firstChild);
53265 this.lockedWrap = new E(cs[3]);
53266 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53267 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53269 this.mainWrap = new E(cs[4]);
53270 this.mainHd = new E(this.mainWrap.dom.firstChild);
53271 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53273 this.footerPanel = new E(cs[5]);
53274 this.footerPanel.enableDisplayMode("block");
53276 this.resizeProxy = new E(cs[6]);
53278 this.headerSelector = String.format(
53279 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53280 this.lockedHd.id, this.mainHd.id
53283 this.splitterSelector = String.format(
53284 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53285 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53288 idToCssName : function(s)
53290 return s.replace(/[^a-z0-9]+/ig, '-');
53293 getHeaderCell : function(index){
53294 return Roo.DomQuery.select(this.headerSelector)[index];
53297 getHeaderCellMeasure : function(index){
53298 return this.getHeaderCell(index).firstChild;
53301 getHeaderCellText : function(index){
53302 return this.getHeaderCell(index).firstChild.firstChild;
53305 getLockedTable : function(){
53306 return this.lockedBody.dom.firstChild;
53309 getBodyTable : function(){
53310 return this.mainBody.dom.firstChild;
53313 getLockedRow : function(index){
53314 return this.getLockedTable().rows[index];
53317 getRow : function(index){
53318 return this.getBodyTable().rows[index];
53321 getRowComposite : function(index){
53323 this.rowEl = new Roo.CompositeElementLite();
53325 var els = [], lrow, mrow;
53326 if(lrow = this.getLockedRow(index)){
53329 if(mrow = this.getRow(index)){
53332 this.rowEl.elements = els;
53336 * Gets the 'td' of the cell
53338 * @param {Integer} rowIndex row to select
53339 * @param {Integer} colIndex column to select
53343 getCell : function(rowIndex, colIndex){
53344 var locked = this.cm.getLockedCount();
53346 if(colIndex < locked){
53347 source = this.lockedBody.dom.firstChild;
53349 source = this.mainBody.dom.firstChild;
53350 colIndex -= locked;
53352 return source.rows[rowIndex].childNodes[colIndex];
53355 getCellText : function(rowIndex, colIndex){
53356 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53359 getCellBox : function(cell){
53360 var b = this.fly(cell).getBox();
53361 if(Roo.isOpera){ // opera fails to report the Y
53362 b.y = cell.offsetTop + this.mainBody.getY();
53367 getCellIndex : function(cell){
53368 var id = String(cell.className).match(this.cellRE);
53370 return parseInt(id[1], 10);
53375 findHeaderIndex : function(n){
53376 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53377 return r ? this.getCellIndex(r) : false;
53380 findHeaderCell : function(n){
53381 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53382 return r ? r : false;
53385 findRowIndex : function(n){
53389 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53390 return r ? r.rowIndex : false;
53393 findCellIndex : function(node){
53394 var stop = this.el.dom;
53395 while(node && node != stop){
53396 if(this.findRE.test(node.className)){
53397 return this.getCellIndex(node);
53399 node = node.parentNode;
53404 getColumnId : function(index){
53405 return this.cm.getColumnId(index);
53408 getSplitters : function()
53410 if(this.splitterSelector){
53411 return Roo.DomQuery.select(this.splitterSelector);
53417 getSplitter : function(index){
53418 return this.getSplitters()[index];
53421 onRowOver : function(e, t){
53423 if((row = this.findRowIndex(t)) !== false){
53424 this.getRowComposite(row).addClass("x-grid-row-over");
53428 onRowOut : function(e, t){
53430 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53431 this.getRowComposite(row).removeClass("x-grid-row-over");
53435 renderHeaders : function(){
53437 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53438 var cb = [], lb = [], sb = [], lsb = [], p = {};
53439 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53440 p.cellId = "x-grid-hd-0-" + i;
53441 p.splitId = "x-grid-csplit-0-" + i;
53442 p.id = cm.getColumnId(i);
53443 p.title = cm.getColumnTooltip(i) || "";
53444 p.value = cm.getColumnHeader(i) || "";
53445 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53446 if(!cm.isLocked(i)){
53447 cb[cb.length] = ct.apply(p);
53448 sb[sb.length] = st.apply(p);
53450 lb[lb.length] = ct.apply(p);
53451 lsb[lsb.length] = st.apply(p);
53454 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53455 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53458 updateHeaders : function(){
53459 var html = this.renderHeaders();
53460 this.lockedHd.update(html[0]);
53461 this.mainHd.update(html[1]);
53465 * Focuses the specified row.
53466 * @param {Number} row The row index
53468 focusRow : function(row)
53470 //Roo.log('GridView.focusRow');
53471 var x = this.scroller.dom.scrollLeft;
53472 this.focusCell(row, 0, false);
53473 this.scroller.dom.scrollLeft = x;
53477 * Focuses the specified cell.
53478 * @param {Number} row The row index
53479 * @param {Number} col The column index
53480 * @param {Boolean} hscroll false to disable horizontal scrolling
53482 focusCell : function(row, col, hscroll)
53484 //Roo.log('GridView.focusCell');
53485 var el = this.ensureVisible(row, col, hscroll);
53486 this.focusEl.alignTo(el, "tl-tl");
53488 this.focusEl.focus();
53490 this.focusEl.focus.defer(1, this.focusEl);
53495 * Scrolls the specified cell into view
53496 * @param {Number} row The row index
53497 * @param {Number} col The column index
53498 * @param {Boolean} hscroll false to disable horizontal scrolling
53500 ensureVisible : function(row, col, hscroll)
53502 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53503 //return null; //disable for testing.
53504 if(typeof row != "number"){
53505 row = row.rowIndex;
53507 if(row < 0 && row >= this.ds.getCount()){
53510 col = (col !== undefined ? col : 0);
53511 var cm = this.grid.colModel;
53512 while(cm.isHidden(col)){
53516 var el = this.getCell(row, col);
53520 var c = this.scroller.dom;
53522 var ctop = parseInt(el.offsetTop, 10);
53523 var cleft = parseInt(el.offsetLeft, 10);
53524 var cbot = ctop + el.offsetHeight;
53525 var cright = cleft + el.offsetWidth;
53527 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53528 var stop = parseInt(c.scrollTop, 10);
53529 var sleft = parseInt(c.scrollLeft, 10);
53530 var sbot = stop + ch;
53531 var sright = sleft + c.clientWidth;
53533 Roo.log('GridView.ensureVisible:' +
53535 ' c.clientHeight:' + c.clientHeight +
53536 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53544 c.scrollTop = ctop;
53545 //Roo.log("set scrolltop to ctop DISABLE?");
53546 }else if(cbot > sbot){
53547 //Roo.log("set scrolltop to cbot-ch");
53548 c.scrollTop = cbot-ch;
53551 if(hscroll !== false){
53553 c.scrollLeft = cleft;
53554 }else if(cright > sright){
53555 c.scrollLeft = cright-c.clientWidth;
53562 updateColumns : function(){
53563 this.grid.stopEditing();
53564 var cm = this.grid.colModel, colIds = this.getColumnIds();
53565 //var totalWidth = cm.getTotalWidth();
53567 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53568 //if(cm.isHidden(i)) continue;
53569 var w = cm.getColumnWidth(i);
53570 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53571 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53573 this.updateSplitters();
53576 generateRules : function(cm){
53577 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53578 Roo.util.CSS.removeStyleSheet(rulesId);
53579 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53580 var cid = cm.getColumnId(i);
53582 if(cm.config[i].align){
53583 align = 'text-align:'+cm.config[i].align+';';
53586 if(cm.isHidden(i)){
53587 hidden = 'display:none;';
53589 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53591 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53592 this.hdSelector, cid, " {\n", align, width, "}\n",
53593 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53594 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53596 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53599 updateSplitters : function(){
53600 var cm = this.cm, s = this.getSplitters();
53601 if(s){ // splitters not created yet
53602 var pos = 0, locked = true;
53603 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53604 if(cm.isHidden(i)) continue;
53605 var w = cm.getColumnWidth(i); // make sure it's a number
53606 if(!cm.isLocked(i) && locked){
53611 s[i].style.left = (pos-this.splitOffset) + "px";
53616 handleHiddenChange : function(colModel, colIndex, hidden){
53618 this.hideColumn(colIndex);
53620 this.unhideColumn(colIndex);
53624 hideColumn : function(colIndex){
53625 var cid = this.getColumnId(colIndex);
53626 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
53627 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
53629 this.updateHeaders();
53631 this.updateSplitters();
53635 unhideColumn : function(colIndex){
53636 var cid = this.getColumnId(colIndex);
53637 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
53638 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
53641 this.updateHeaders();
53643 this.updateSplitters();
53647 insertRows : function(dm, firstRow, lastRow, isUpdate){
53648 if(firstRow == 0 && lastRow == dm.getCount()-1){
53652 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
53654 var s = this.getScrollState();
53655 var markup = this.renderRows(firstRow, lastRow);
53656 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
53657 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
53658 this.restoreScroll(s);
53660 this.fireEvent("rowsinserted", this, firstRow, lastRow);
53661 this.syncRowHeights(firstRow, lastRow);
53662 this.stripeRows(firstRow);
53668 bufferRows : function(markup, target, index){
53669 var before = null, trows = target.rows, tbody = target.tBodies[0];
53670 if(index < trows.length){
53671 before = trows[index];
53673 var b = document.createElement("div");
53674 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
53675 var rows = b.firstChild.rows;
53676 for(var i = 0, len = rows.length; i < len; i++){
53678 tbody.insertBefore(rows[0], before);
53680 tbody.appendChild(rows[0]);
53687 deleteRows : function(dm, firstRow, lastRow){
53688 if(dm.getRowCount()<1){
53689 this.fireEvent("beforerefresh", this);
53690 this.mainBody.update("");
53691 this.lockedBody.update("");
53692 this.fireEvent("refresh", this);
53694 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
53695 var bt = this.getBodyTable();
53696 var tbody = bt.firstChild;
53697 var rows = bt.rows;
53698 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
53699 tbody.removeChild(rows[firstRow]);
53701 this.stripeRows(firstRow);
53702 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
53706 updateRows : function(dataSource, firstRow, lastRow){
53707 var s = this.getScrollState();
53709 this.restoreScroll(s);
53712 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
53716 this.updateHeaderSortState();
53719 getScrollState : function(){
53721 var sb = this.scroller.dom;
53722 return {left: sb.scrollLeft, top: sb.scrollTop};
53725 stripeRows : function(startRow){
53726 if(!this.grid.stripeRows || this.ds.getCount() < 1){
53729 startRow = startRow || 0;
53730 var rows = this.getBodyTable().rows;
53731 var lrows = this.getLockedTable().rows;
53732 var cls = ' x-grid-row-alt ';
53733 for(var i = startRow, len = rows.length; i < len; i++){
53734 var row = rows[i], lrow = lrows[i];
53735 var isAlt = ((i+1) % 2 == 0);
53736 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
53737 if(isAlt == hasAlt){
53741 row.className += " x-grid-row-alt";
53743 row.className = row.className.replace("x-grid-row-alt", "");
53746 lrow.className = row.className;
53751 restoreScroll : function(state){
53752 //Roo.log('GridView.restoreScroll');
53753 var sb = this.scroller.dom;
53754 sb.scrollLeft = state.left;
53755 sb.scrollTop = state.top;
53759 syncScroll : function(){
53760 //Roo.log('GridView.syncScroll');
53761 var sb = this.scroller.dom;
53762 var sh = this.mainHd.dom;
53763 var bs = this.mainBody.dom;
53764 var lv = this.lockedBody.dom;
53765 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
53766 lv.scrollTop = bs.scrollTop = sb.scrollTop;
53769 handleScroll : function(e){
53771 var sb = this.scroller.dom;
53772 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
53776 handleWheel : function(e){
53777 var d = e.getWheelDelta();
53778 this.scroller.dom.scrollTop -= d*22;
53779 // set this here to prevent jumpy scrolling on large tables
53780 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
53784 renderRows : function(startRow, endRow){
53785 // pull in all the crap needed to render rows
53786 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
53787 var colCount = cm.getColumnCount();
53789 if(ds.getCount() < 1){
53793 // build a map for all the columns
53795 for(var i = 0; i < colCount; i++){
53796 var name = cm.getDataIndex(i);
53798 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
53799 renderer : cm.getRenderer(i),
53800 id : cm.getColumnId(i),
53801 locked : cm.isLocked(i)
53805 startRow = startRow || 0;
53806 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
53808 // records to render
53809 var rs = ds.getRange(startRow, endRow);
53811 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
53814 // As much as I hate to duplicate code, this was branched because FireFox really hates
53815 // [].join("") on strings. The performance difference was substantial enough to
53816 // branch this function
53817 doRender : Roo.isGecko ?
53818 function(cs, rs, ds, startRow, colCount, stripe){
53819 var ts = this.templates, ct = ts.cell, rt = ts.row;
53821 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53823 var hasListener = this.grid.hasListener('rowclass');
53825 for(var j = 0, len = rs.length; j < len; j++){
53826 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
53827 for(var i = 0; i < colCount; i++){
53829 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53831 p.css = p.attr = "";
53832 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53833 if(p.value == undefined || p.value === "") p.value = " ";
53834 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53835 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53837 var markup = ct.apply(p);
53845 if(stripe && ((rowIndex+1) % 2 == 0)){
53846 alt.push("x-grid-row-alt")
53849 alt.push( " x-grid-dirty-row");
53852 if(this.getRowClass){
53853 alt.push(this.getRowClass(r, rowIndex));
53859 rowIndex : rowIndex,
53862 this.grid.fireEvent('rowclass', this, rowcfg);
53863 alt.push(rowcfg.rowClass);
53865 rp.alt = alt.join(" ");
53866 lbuf+= rt.apply(rp);
53868 buf+= rt.apply(rp);
53870 return [lbuf, buf];
53872 function(cs, rs, ds, startRow, colCount, stripe){
53873 var ts = this.templates, ct = ts.cell, rt = ts.row;
53875 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53876 var hasListener = this.grid.hasListener('rowclass');
53879 for(var j = 0, len = rs.length; j < len; j++){
53880 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
53881 for(var i = 0; i < colCount; i++){
53883 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53885 p.css = p.attr = "";
53886 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53887 if(p.value == undefined || p.value === "") p.value = " ";
53888 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53889 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53892 var markup = ct.apply(p);
53894 cb[cb.length] = markup;
53896 lcb[lcb.length] = markup;
53900 if(stripe && ((rowIndex+1) % 2 == 0)){
53901 alt.push( "x-grid-row-alt");
53904 alt.push(" x-grid-dirty-row");
53907 if(this.getRowClass){
53908 alt.push( this.getRowClass(r, rowIndex));
53914 rowIndex : rowIndex,
53917 this.grid.fireEvent('rowclass', this, rowcfg);
53918 alt.push(rowcfg.rowClass);
53920 rp.alt = alt.join(" ");
53921 rp.cells = lcb.join("");
53922 lbuf[lbuf.length] = rt.apply(rp);
53923 rp.cells = cb.join("");
53924 buf[buf.length] = rt.apply(rp);
53926 return [lbuf.join(""), buf.join("")];
53929 renderBody : function(){
53930 var markup = this.renderRows();
53931 var bt = this.templates.body;
53932 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
53936 * Refreshes the grid
53937 * @param {Boolean} headersToo
53939 refresh : function(headersToo){
53940 this.fireEvent("beforerefresh", this);
53941 this.grid.stopEditing();
53942 var result = this.renderBody();
53943 this.lockedBody.update(result[0]);
53944 this.mainBody.update(result[1]);
53945 if(headersToo === true){
53946 this.updateHeaders();
53947 this.updateColumns();
53948 this.updateSplitters();
53949 this.updateHeaderSortState();
53951 this.syncRowHeights();
53953 this.fireEvent("refresh", this);
53956 handleColumnMove : function(cm, oldIndex, newIndex){
53957 this.indexMap = null;
53958 var s = this.getScrollState();
53959 this.refresh(true);
53960 this.restoreScroll(s);
53961 this.afterMove(newIndex);
53964 afterMove : function(colIndex){
53965 if(this.enableMoveAnim && Roo.enableFx){
53966 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
53968 // if multisort - fix sortOrder, and reload..
53969 if (this.grid.dataSource.multiSort) {
53970 // the we can call sort again..
53971 var dm = this.grid.dataSource;
53972 var cm = this.grid.colModel;
53974 for(var i = 0; i < cm.config.length; i++ ) {
53976 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
53977 continue; // dont' bother, it's not in sort list or being set.
53980 so.push(cm.config[i].dataIndex);
53983 dm.load(dm.lastOptions);
53990 updateCell : function(dm, rowIndex, dataIndex){
53991 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
53992 if(typeof colIndex == "undefined"){ // not present in grid
53995 var cm = this.grid.colModel;
53996 var cell = this.getCell(rowIndex, colIndex);
53997 var cellText = this.getCellText(rowIndex, colIndex);
54000 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
54001 id : cm.getColumnId(colIndex),
54002 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
54004 var renderer = cm.getRenderer(colIndex);
54005 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
54006 if(typeof val == "undefined" || val === "") val = " ";
54007 cellText.innerHTML = val;
54008 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
54009 this.syncRowHeights(rowIndex, rowIndex);
54012 calcColumnWidth : function(colIndex, maxRowsToMeasure){
54014 if(this.grid.autoSizeHeaders){
54015 var h = this.getHeaderCellMeasure(colIndex);
54016 maxWidth = Math.max(maxWidth, h.scrollWidth);
54019 if(this.cm.isLocked(colIndex)){
54020 tb = this.getLockedTable();
54023 tb = this.getBodyTable();
54024 index = colIndex - this.cm.getLockedCount();
54027 var rows = tb.rows;
54028 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
54029 for(var i = 0; i < stopIndex; i++){
54030 var cell = rows[i].childNodes[index].firstChild;
54031 maxWidth = Math.max(maxWidth, cell.scrollWidth);
54034 return maxWidth + /*margin for error in IE*/ 5;
54037 * Autofit a column to its content.
54038 * @param {Number} colIndex
54039 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
54041 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
54042 if(this.cm.isHidden(colIndex)){
54043 return; // can't calc a hidden column
54046 var cid = this.cm.getColumnId(colIndex);
54047 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
54048 if(this.grid.autoSizeHeaders){
54049 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
54052 var newWidth = this.calcColumnWidth(colIndex);
54053 this.cm.setColumnWidth(colIndex,
54054 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
54055 if(!suppressEvent){
54056 this.grid.fireEvent("columnresize", colIndex, newWidth);
54061 * Autofits all columns to their content and then expands to fit any extra space in the grid
54063 autoSizeColumns : function(){
54064 var cm = this.grid.colModel;
54065 var colCount = cm.getColumnCount();
54066 for(var i = 0; i < colCount; i++){
54067 this.autoSizeColumn(i, true, true);
54069 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
54072 this.updateColumns();
54078 * Autofits all columns to the grid's width proportionate with their current size
54079 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
54081 fitColumns : function(reserveScrollSpace){
54082 var cm = this.grid.colModel;
54083 var colCount = cm.getColumnCount();
54087 for (i = 0; i < colCount; i++){
54088 if(!cm.isHidden(i) && !cm.isFixed(i)){
54089 w = cm.getColumnWidth(i);
54095 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
54096 if(reserveScrollSpace){
54099 var frac = (avail - cm.getTotalWidth())/width;
54100 while (cols.length){
54103 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
54105 this.updateColumns();
54109 onRowSelect : function(rowIndex){
54110 var row = this.getRowComposite(rowIndex);
54111 row.addClass("x-grid-row-selected");
54114 onRowDeselect : function(rowIndex){
54115 var row = this.getRowComposite(rowIndex);
54116 row.removeClass("x-grid-row-selected");
54119 onCellSelect : function(row, col){
54120 var cell = this.getCell(row, col);
54122 Roo.fly(cell).addClass("x-grid-cell-selected");
54126 onCellDeselect : function(row, col){
54127 var cell = this.getCell(row, col);
54129 Roo.fly(cell).removeClass("x-grid-cell-selected");
54133 updateHeaderSortState : function(){
54135 // sort state can be single { field: xxx, direction : yyy}
54136 // or { xxx=>ASC , yyy : DESC ..... }
54139 if (!this.ds.multiSort) {
54140 var state = this.ds.getSortState();
54144 mstate[state.field] = state.direction;
54145 // FIXME... - this is not used here.. but might be elsewhere..
54146 this.sortState = state;
54149 mstate = this.ds.sortToggle;
54151 //remove existing sort classes..
54153 var sc = this.sortClasses;
54154 var hds = this.el.select(this.headerSelector).removeClass(sc);
54156 for(var f in mstate) {
54158 var sortColumn = this.cm.findColumnIndex(f);
54160 if(sortColumn != -1){
54161 var sortDir = mstate[f];
54162 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54171 handleHeaderClick : function(g, index,e){
54173 Roo.log("header click");
54176 // touch events on header are handled by context
54177 this.handleHdCtx(g,index,e);
54182 if(this.headersDisabled){
54185 var dm = g.dataSource, cm = g.colModel;
54186 if(!cm.isSortable(index)){
54191 if (dm.multiSort) {
54192 // update the sortOrder
54194 for(var i = 0; i < cm.config.length; i++ ) {
54196 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54197 continue; // dont' bother, it's not in sort list or being set.
54200 so.push(cm.config[i].dataIndex);
54206 dm.sort(cm.getDataIndex(index));
54210 destroy : function(){
54212 this.colMenu.removeAll();
54213 Roo.menu.MenuMgr.unregister(this.colMenu);
54214 this.colMenu.getEl().remove();
54215 delete this.colMenu;
54218 this.hmenu.removeAll();
54219 Roo.menu.MenuMgr.unregister(this.hmenu);
54220 this.hmenu.getEl().remove();
54223 if(this.grid.enableColumnMove){
54224 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54226 for(var dd in dds){
54227 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54228 var elid = dds[dd].dragElId;
54230 Roo.get(elid).remove();
54231 } else if(dds[dd].config.isTarget){
54232 dds[dd].proxyTop.remove();
54233 dds[dd].proxyBottom.remove();
54236 if(Roo.dd.DDM.locationCache[dd]){
54237 delete Roo.dd.DDM.locationCache[dd];
54240 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54243 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54244 this.bind(null, null);
54245 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54248 handleLockChange : function(){
54249 this.refresh(true);
54252 onDenyColumnLock : function(){
54256 onDenyColumnHide : function(){
54260 handleHdMenuClick : function(item){
54261 var index = this.hdCtxIndex;
54262 var cm = this.cm, ds = this.ds;
54265 ds.sort(cm.getDataIndex(index), "ASC");
54268 ds.sort(cm.getDataIndex(index), "DESC");
54271 var lc = cm.getLockedCount();
54272 if(cm.getColumnCount(true) <= lc+1){
54273 this.onDenyColumnLock();
54277 cm.setLocked(index, true, true);
54278 cm.moveColumn(index, lc);
54279 this.grid.fireEvent("columnmove", index, lc);
54281 cm.setLocked(index, true);
54285 var lc = cm.getLockedCount();
54286 if((lc-1) != index){
54287 cm.setLocked(index, false, true);
54288 cm.moveColumn(index, lc-1);
54289 this.grid.fireEvent("columnmove", index, lc-1);
54291 cm.setLocked(index, false);
54294 case 'wider': // used to expand cols on touch..
54296 var cw = cm.getColumnWidth(index);
54297 cw += (item.id == 'wider' ? 1 : -1) * 50;
54298 cw = Math.max(0, cw);
54299 cw = Math.min(cw,4000);
54300 cm.setColumnWidth(index, cw);
54304 index = cm.getIndexById(item.id.substr(4));
54306 if(item.checked && cm.getColumnCount(true) <= 1){
54307 this.onDenyColumnHide();
54310 cm.setHidden(index, item.checked);
54316 beforeColMenuShow : function(){
54317 var cm = this.cm, colCount = cm.getColumnCount();
54318 this.colMenu.removeAll();
54319 for(var i = 0; i < colCount; i++){
54320 this.colMenu.add(new Roo.menu.CheckItem({
54321 id: "col-"+cm.getColumnId(i),
54322 text: cm.getColumnHeader(i),
54323 checked: !cm.isHidden(i),
54329 handleHdCtx : function(g, index, e){
54331 var hd = this.getHeaderCell(index);
54332 this.hdCtxIndex = index;
54333 var ms = this.hmenu.items, cm = this.cm;
54334 ms.get("asc").setDisabled(!cm.isSortable(index));
54335 ms.get("desc").setDisabled(!cm.isSortable(index));
54336 if(this.grid.enableColLock !== false){
54337 ms.get("lock").setDisabled(cm.isLocked(index));
54338 ms.get("unlock").setDisabled(!cm.isLocked(index));
54340 this.hmenu.show(hd, "tl-bl");
54343 handleHdOver : function(e){
54344 var hd = this.findHeaderCell(e.getTarget());
54345 if(hd && !this.headersDisabled){
54346 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54347 this.fly(hd).addClass("x-grid-hd-over");
54352 handleHdOut : function(e){
54353 var hd = this.findHeaderCell(e.getTarget());
54355 this.fly(hd).removeClass("x-grid-hd-over");
54359 handleSplitDblClick : function(e, t){
54360 var i = this.getCellIndex(t);
54361 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54362 this.autoSizeColumn(i, true);
54367 render : function(){
54370 var colCount = cm.getColumnCount();
54372 if(this.grid.monitorWindowResize === true){
54373 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54375 var header = this.renderHeaders();
54376 var body = this.templates.body.apply({rows:""});
54377 var html = this.templates.master.apply({
54380 lockedHeader: header[0],
54384 //this.updateColumns();
54386 this.grid.getGridEl().dom.innerHTML = html;
54388 this.initElements();
54390 // a kludge to fix the random scolling effect in webkit
54391 this.el.on("scroll", function() {
54392 this.el.dom.scrollTop=0; // hopefully not recursive..
54395 this.scroller.on("scroll", this.handleScroll, this);
54396 this.lockedBody.on("mousewheel", this.handleWheel, this);
54397 this.mainBody.on("mousewheel", this.handleWheel, this);
54399 this.mainHd.on("mouseover", this.handleHdOver, this);
54400 this.mainHd.on("mouseout", this.handleHdOut, this);
54401 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54402 {delegate: "."+this.splitClass});
54404 this.lockedHd.on("mouseover", this.handleHdOver, this);
54405 this.lockedHd.on("mouseout", this.handleHdOut, this);
54406 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54407 {delegate: "."+this.splitClass});
54409 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54410 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54413 this.updateSplitters();
54415 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54416 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54417 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54420 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54421 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54423 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54424 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54426 if(this.grid.enableColLock !== false){
54427 this.hmenu.add('-',
54428 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54429 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54433 this.hmenu.add('-',
54434 {id:"wider", text: this.columnsWiderText},
54435 {id:"narrow", text: this.columnsNarrowText }
54441 if(this.grid.enableColumnHide !== false){
54443 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54444 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54445 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54447 this.hmenu.add('-',
54448 {id:"columns", text: this.columnsText, menu: this.colMenu}
54451 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54453 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54456 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54457 this.dd = new Roo.grid.GridDragZone(this.grid, {
54458 ddGroup : this.grid.ddGroup || 'GridDD'
54464 for(var i = 0; i < colCount; i++){
54465 if(cm.isHidden(i)){
54466 this.hideColumn(i);
54468 if(cm.config[i].align){
54469 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54470 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54474 this.updateHeaderSortState();
54476 this.beforeInitialResize();
54479 // two part rendering gives faster view to the user
54480 this.renderPhase2.defer(1, this);
54483 renderPhase2 : function(){
54484 // render the rows now
54486 if(this.grid.autoSizeColumns){
54487 this.autoSizeColumns();
54491 beforeInitialResize : function(){
54495 onColumnSplitterMoved : function(i, w){
54496 this.userResized = true;
54497 var cm = this.grid.colModel;
54498 cm.setColumnWidth(i, w, true);
54499 var cid = cm.getColumnId(i);
54500 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54501 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54502 this.updateSplitters();
54504 this.grid.fireEvent("columnresize", i, w);
54507 syncRowHeights : function(startIndex, endIndex){
54508 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54509 startIndex = startIndex || 0;
54510 var mrows = this.getBodyTable().rows;
54511 var lrows = this.getLockedTable().rows;
54512 var len = mrows.length-1;
54513 endIndex = Math.min(endIndex || len, len);
54514 for(var i = startIndex; i <= endIndex; i++){
54515 var m = mrows[i], l = lrows[i];
54516 var h = Math.max(m.offsetHeight, l.offsetHeight);
54517 m.style.height = l.style.height = h + "px";
54522 layout : function(initialRender, is2ndPass){
54524 var auto = g.autoHeight;
54525 var scrollOffset = 16;
54526 var c = g.getGridEl(), cm = this.cm,
54527 expandCol = g.autoExpandColumn,
54529 //c.beginMeasure();
54531 if(!c.dom.offsetWidth){ // display:none?
54533 this.lockedWrap.show();
54534 this.mainWrap.show();
54539 var hasLock = this.cm.isLocked(0);
54541 var tbh = this.headerPanel.getHeight();
54542 var bbh = this.footerPanel.getHeight();
54545 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54546 var newHeight = ch + c.getBorderWidth("tb");
54548 newHeight = Math.min(g.maxHeight, newHeight);
54550 c.setHeight(newHeight);
54554 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54557 var s = this.scroller;
54559 var csize = c.getSize(true);
54561 this.el.setSize(csize.width, csize.height);
54563 this.headerPanel.setWidth(csize.width);
54564 this.footerPanel.setWidth(csize.width);
54566 var hdHeight = this.mainHd.getHeight();
54567 var vw = csize.width;
54568 var vh = csize.height - (tbh + bbh);
54572 var bt = this.getBodyTable();
54573 var ltWidth = hasLock ?
54574 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54576 var scrollHeight = bt.offsetHeight;
54577 var scrollWidth = ltWidth + bt.offsetWidth;
54578 var vscroll = false, hscroll = false;
54580 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54582 var lw = this.lockedWrap, mw = this.mainWrap;
54583 var lb = this.lockedBody, mb = this.mainBody;
54585 setTimeout(function(){
54586 var t = s.dom.offsetTop;
54587 var w = s.dom.clientWidth,
54588 h = s.dom.clientHeight;
54591 lw.setSize(ltWidth, h);
54593 mw.setLeftTop(ltWidth, t);
54594 mw.setSize(w-ltWidth, h);
54596 lb.setHeight(h-hdHeight);
54597 mb.setHeight(h-hdHeight);
54599 if(is2ndPass !== true && !gv.userResized && expandCol){
54600 // high speed resize without full column calculation
54602 var ci = cm.getIndexById(expandCol);
54604 ci = cm.findColumnIndex(expandCol);
54606 ci = Math.max(0, ci); // make sure it's got at least the first col.
54607 var expandId = cm.getColumnId(ci);
54608 var tw = cm.getTotalWidth(false);
54609 var currentWidth = cm.getColumnWidth(ci);
54610 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54611 if(currentWidth != cw){
54612 cm.setColumnWidth(ci, cw, true);
54613 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54614 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54615 gv.updateSplitters();
54616 gv.layout(false, true);
54628 onWindowResize : function(){
54629 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
54635 appendFooter : function(parentEl){
54639 sortAscText : "Sort Ascending",
54640 sortDescText : "Sort Descending",
54641 lockText : "Lock Column",
54642 unlockText : "Unlock Column",
54643 columnsText : "Columns",
54645 columnsWiderText : "Wider",
54646 columnsNarrowText : "Thinner"
54650 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
54651 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
54652 this.proxy.el.addClass('x-grid3-col-dd');
54655 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
54656 handleMouseDown : function(e){
54660 callHandleMouseDown : function(e){
54661 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
54666 * Ext JS Library 1.1.1
54667 * Copyright(c) 2006-2007, Ext JS, LLC.
54669 * Originally Released Under LGPL - original licence link has changed is not relivant.
54672 * <script type="text/javascript">
54676 // This is a support class used internally by the Grid components
54677 Roo.grid.SplitDragZone = function(grid, hd, hd2){
54679 this.view = grid.getView();
54680 this.proxy = this.view.resizeProxy;
54681 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
54682 "gridSplitters" + this.grid.getGridEl().id, {
54683 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
54685 this.setHandleElId(Roo.id(hd));
54686 this.setOuterHandleElId(Roo.id(hd2));
54687 this.scroll = false;
54689 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
54690 fly: Roo.Element.fly,
54692 b4StartDrag : function(x, y){
54693 this.view.headersDisabled = true;
54694 this.proxy.setHeight(this.view.mainWrap.getHeight());
54695 var w = this.cm.getColumnWidth(this.cellIndex);
54696 var minw = Math.max(w-this.grid.minColumnWidth, 0);
54697 this.resetConstraints();
54698 this.setXConstraint(minw, 1000);
54699 this.setYConstraint(0, 0);
54700 this.minX = x - minw;
54701 this.maxX = x + 1000;
54703 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
54707 handleMouseDown : function(e){
54708 ev = Roo.EventObject.setEvent(e);
54709 var t = this.fly(ev.getTarget());
54710 if(t.hasClass("x-grid-split")){
54711 this.cellIndex = this.view.getCellIndex(t.dom);
54712 this.split = t.dom;
54713 this.cm = this.grid.colModel;
54714 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
54715 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
54720 endDrag : function(e){
54721 this.view.headersDisabled = false;
54722 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
54723 var diff = endX - this.startPos;
54724 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
54727 autoOffset : function(){
54728 this.setDelta(0,0);
54732 * Ext JS Library 1.1.1
54733 * Copyright(c) 2006-2007, Ext JS, LLC.
54735 * Originally Released Under LGPL - original licence link has changed is not relivant.
54738 * <script type="text/javascript">
54742 // This is a support class used internally by the Grid components
54743 Roo.grid.GridDragZone = function(grid, config){
54744 this.view = grid.getView();
54745 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
54746 if(this.view.lockedBody){
54747 this.setHandleElId(Roo.id(this.view.mainBody.dom));
54748 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
54750 this.scroll = false;
54752 this.ddel = document.createElement('div');
54753 this.ddel.className = 'x-grid-dd-wrap';
54756 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
54757 ddGroup : "GridDD",
54759 getDragData : function(e){
54760 var t = Roo.lib.Event.getTarget(e);
54761 var rowIndex = this.view.findRowIndex(t);
54762 var sm = this.grid.selModel;
54764 //Roo.log(rowIndex);
54766 if (sm.getSelectedCell) {
54767 // cell selection..
54768 if (!sm.getSelectedCell()) {
54771 if (rowIndex != sm.getSelectedCell()[0]) {
54777 if(rowIndex !== false){
54782 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
54784 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
54787 if (e.hasModifier()){
54788 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
54791 Roo.log("getDragData");
54796 rowIndex: rowIndex,
54797 selections:sm.getSelections ? sm.getSelections() : (
54798 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
54805 onInitDrag : function(e){
54806 var data = this.dragData;
54807 this.ddel.innerHTML = this.grid.getDragDropText();
54808 this.proxy.update(this.ddel);
54809 // fire start drag?
54812 afterRepair : function(){
54813 this.dragging = false;
54816 getRepairXY : function(e, data){
54820 onEndDrag : function(data, e){
54824 onValidDrop : function(dd, e, id){
54829 beforeInvalidDrop : function(e, id){
54834 * Ext JS Library 1.1.1
54835 * Copyright(c) 2006-2007, Ext JS, LLC.
54837 * Originally Released Under LGPL - original licence link has changed is not relivant.
54840 * <script type="text/javascript">
54845 * @class Roo.grid.ColumnModel
54846 * @extends Roo.util.Observable
54847 * This is the default implementation of a ColumnModel used by the Grid. It defines
54848 * the columns in the grid.
54851 var colModel = new Roo.grid.ColumnModel([
54852 {header: "Ticker", width: 60, sortable: true, locked: true},
54853 {header: "Company Name", width: 150, sortable: true},
54854 {header: "Market Cap.", width: 100, sortable: true},
54855 {header: "$ Sales", width: 100, sortable: true, renderer: money},
54856 {header: "Employees", width: 100, sortable: true, resizable: false}
54861 * The config options listed for this class are options which may appear in each
54862 * individual column definition.
54863 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
54865 * @param {Object} config An Array of column config objects. See this class's
54866 * config objects for details.
54868 Roo.grid.ColumnModel = function(config){
54870 * The config passed into the constructor
54872 this.config = config;
54875 // if no id, create one
54876 // if the column does not have a dataIndex mapping,
54877 // map it to the order it is in the config
54878 for(var i = 0, len = config.length; i < len; i++){
54880 if(typeof c.dataIndex == "undefined"){
54883 if(typeof c.renderer == "string"){
54884 c.renderer = Roo.util.Format[c.renderer];
54886 if(typeof c.id == "undefined"){
54889 if(c.editor && c.editor.xtype){
54890 c.editor = Roo.factory(c.editor, Roo.grid);
54892 if(c.editor && c.editor.isFormField){
54893 c.editor = new Roo.grid.GridEditor(c.editor);
54895 this.lookup[c.id] = c;
54899 * The width of columns which have no width specified (defaults to 100)
54902 this.defaultWidth = 100;
54905 * Default sortable of columns which have no sortable specified (defaults to false)
54908 this.defaultSortable = false;
54912 * @event widthchange
54913 * Fires when the width of a column changes.
54914 * @param {ColumnModel} this
54915 * @param {Number} columnIndex The column index
54916 * @param {Number} newWidth The new width
54918 "widthchange": true,
54920 * @event headerchange
54921 * Fires when the text of a header changes.
54922 * @param {ColumnModel} this
54923 * @param {Number} columnIndex The column index
54924 * @param {Number} newText The new header text
54926 "headerchange": true,
54928 * @event hiddenchange
54929 * Fires when a column is hidden or "unhidden".
54930 * @param {ColumnModel} this
54931 * @param {Number} columnIndex The column index
54932 * @param {Boolean} hidden true if hidden, false otherwise
54934 "hiddenchange": true,
54936 * @event columnmoved
54937 * Fires when a column is moved.
54938 * @param {ColumnModel} this
54939 * @param {Number} oldIndex
54940 * @param {Number} newIndex
54942 "columnmoved" : true,
54944 * @event columlockchange
54945 * Fires when a column's locked state is changed
54946 * @param {ColumnModel} this
54947 * @param {Number} colIndex
54948 * @param {Boolean} locked true if locked
54950 "columnlockchange" : true
54952 Roo.grid.ColumnModel.superclass.constructor.call(this);
54954 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
54956 * @cfg {String} header The header text to display in the Grid view.
54959 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
54960 * {@link Roo.data.Record} definition from which to draw the column's value. If not
54961 * specified, the column's index is used as an index into the Record's data Array.
54964 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
54965 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
54968 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
54969 * Defaults to the value of the {@link #defaultSortable} property.
54970 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
54973 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
54976 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
54979 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
54982 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
54985 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
54986 * given the cell's data value. See {@link #setRenderer}. If not specified, the
54987 * default renderer uses the raw data value. If an object is returned (bootstrap only)
54988 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
54991 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
54994 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
54998 * Returns the id of the column at the specified index.
54999 * @param {Number} index The column index
55000 * @return {String} the id
55002 getColumnId : function(index){
55003 return this.config[index].id;
55007 * Returns the column for a specified id.
55008 * @param {String} id The column id
55009 * @return {Object} the column
55011 getColumnById : function(id){
55012 return this.lookup[id];
55017 * Returns the column for a specified dataIndex.
55018 * @param {String} dataIndex The column dataIndex
55019 * @return {Object|Boolean} the column or false if not found
55021 getColumnByDataIndex: function(dataIndex){
55022 var index = this.findColumnIndex(dataIndex);
55023 return index > -1 ? this.config[index] : false;
55027 * Returns the index for a specified column id.
55028 * @param {String} id The column id
55029 * @return {Number} the index, or -1 if not found
55031 getIndexById : function(id){
55032 for(var i = 0, len = this.config.length; i < len; i++){
55033 if(this.config[i].id == id){
55041 * Returns the index for a specified column dataIndex.
55042 * @param {String} dataIndex The column dataIndex
55043 * @return {Number} the index, or -1 if not found
55046 findColumnIndex : function(dataIndex){
55047 for(var i = 0, len = this.config.length; i < len; i++){
55048 if(this.config[i].dataIndex == dataIndex){
55056 moveColumn : function(oldIndex, newIndex){
55057 var c = this.config[oldIndex];
55058 this.config.splice(oldIndex, 1);
55059 this.config.splice(newIndex, 0, c);
55060 this.dataMap = null;
55061 this.fireEvent("columnmoved", this, oldIndex, newIndex);
55064 isLocked : function(colIndex){
55065 return this.config[colIndex].locked === true;
55068 setLocked : function(colIndex, value, suppressEvent){
55069 if(this.isLocked(colIndex) == value){
55072 this.config[colIndex].locked = value;
55073 if(!suppressEvent){
55074 this.fireEvent("columnlockchange", this, colIndex, value);
55078 getTotalLockedWidth : function(){
55079 var totalWidth = 0;
55080 for(var i = 0; i < this.config.length; i++){
55081 if(this.isLocked(i) && !this.isHidden(i)){
55082 this.totalWidth += this.getColumnWidth(i);
55088 getLockedCount : function(){
55089 for(var i = 0, len = this.config.length; i < len; i++){
55090 if(!this.isLocked(i)){
55097 * Returns the number of columns.
55100 getColumnCount : function(visibleOnly){
55101 if(visibleOnly === true){
55103 for(var i = 0, len = this.config.length; i < len; i++){
55104 if(!this.isHidden(i)){
55110 return this.config.length;
55114 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
55115 * @param {Function} fn
55116 * @param {Object} scope (optional)
55117 * @return {Array} result
55119 getColumnsBy : function(fn, scope){
55121 for(var i = 0, len = this.config.length; i < len; i++){
55122 var c = this.config[i];
55123 if(fn.call(scope||this, c, i) === true){
55131 * Returns true if the specified column is sortable.
55132 * @param {Number} col The column index
55133 * @return {Boolean}
55135 isSortable : function(col){
55136 if(typeof this.config[col].sortable == "undefined"){
55137 return this.defaultSortable;
55139 return this.config[col].sortable;
55143 * Returns the rendering (formatting) function defined for the column.
55144 * @param {Number} col The column index.
55145 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
55147 getRenderer : function(col){
55148 if(!this.config[col].renderer){
55149 return Roo.grid.ColumnModel.defaultRenderer;
55151 return this.config[col].renderer;
55155 * Sets the rendering (formatting) function for a column.
55156 * @param {Number} col The column index
55157 * @param {Function} fn The function to use to process the cell's raw data
55158 * to return HTML markup for the grid view. The render function is called with
55159 * the following parameters:<ul>
55160 * <li>Data value.</li>
55161 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
55162 * <li>css A CSS style string to apply to the table cell.</li>
55163 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55164 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55165 * <li>Row index</li>
55166 * <li>Column index</li>
55167 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55169 setRenderer : function(col, fn){
55170 this.config[col].renderer = fn;
55174 * Returns the width for the specified column.
55175 * @param {Number} col The column index
55178 getColumnWidth : function(col){
55179 return this.config[col].width * 1 || this.defaultWidth;
55183 * Sets the width for a column.
55184 * @param {Number} col The column index
55185 * @param {Number} width The new width
55187 setColumnWidth : function(col, width, suppressEvent){
55188 this.config[col].width = width;
55189 this.totalWidth = null;
55190 if(!suppressEvent){
55191 this.fireEvent("widthchange", this, col, width);
55196 * Returns the total width of all columns.
55197 * @param {Boolean} includeHidden True to include hidden column widths
55200 getTotalWidth : function(includeHidden){
55201 if(!this.totalWidth){
55202 this.totalWidth = 0;
55203 for(var i = 0, len = this.config.length; i < len; i++){
55204 if(includeHidden || !this.isHidden(i)){
55205 this.totalWidth += this.getColumnWidth(i);
55209 return this.totalWidth;
55213 * Returns the header for the specified column.
55214 * @param {Number} col The column index
55217 getColumnHeader : function(col){
55218 return this.config[col].header;
55222 * Sets the header for a column.
55223 * @param {Number} col The column index
55224 * @param {String} header The new header
55226 setColumnHeader : function(col, header){
55227 this.config[col].header = header;
55228 this.fireEvent("headerchange", this, col, header);
55232 * Returns the tooltip for the specified column.
55233 * @param {Number} col The column index
55236 getColumnTooltip : function(col){
55237 return this.config[col].tooltip;
55240 * Sets the tooltip for a column.
55241 * @param {Number} col The column index
55242 * @param {String} tooltip The new tooltip
55244 setColumnTooltip : function(col, tooltip){
55245 this.config[col].tooltip = tooltip;
55249 * Returns the dataIndex for the specified column.
55250 * @param {Number} col The column index
55253 getDataIndex : function(col){
55254 return this.config[col].dataIndex;
55258 * Sets the dataIndex for a column.
55259 * @param {Number} col The column index
55260 * @param {Number} dataIndex The new dataIndex
55262 setDataIndex : function(col, dataIndex){
55263 this.config[col].dataIndex = dataIndex;
55269 * Returns true if the cell is editable.
55270 * @param {Number} colIndex The column index
55271 * @param {Number} rowIndex The row index
55272 * @return {Boolean}
55274 isCellEditable : function(colIndex, rowIndex){
55275 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55279 * Returns the editor defined for the cell/column.
55280 * return false or null to disable editing.
55281 * @param {Number} colIndex The column index
55282 * @param {Number} rowIndex The row index
55285 getCellEditor : function(colIndex, rowIndex){
55286 return this.config[colIndex].editor;
55290 * Sets if a column is editable.
55291 * @param {Number} col The column index
55292 * @param {Boolean} editable True if the column is editable
55294 setEditable : function(col, editable){
55295 this.config[col].editable = editable;
55300 * Returns true if the column is hidden.
55301 * @param {Number} colIndex The column index
55302 * @return {Boolean}
55304 isHidden : function(colIndex){
55305 return this.config[colIndex].hidden;
55310 * Returns true if the column width cannot be changed
55312 isFixed : function(colIndex){
55313 return this.config[colIndex].fixed;
55317 * Returns true if the column can be resized
55318 * @return {Boolean}
55320 isResizable : function(colIndex){
55321 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55324 * Sets if a column is hidden.
55325 * @param {Number} colIndex The column index
55326 * @param {Boolean} hidden True if the column is hidden
55328 setHidden : function(colIndex, hidden){
55329 this.config[colIndex].hidden = hidden;
55330 this.totalWidth = null;
55331 this.fireEvent("hiddenchange", this, colIndex, hidden);
55335 * Sets the editor for a column.
55336 * @param {Number} col The column index
55337 * @param {Object} editor The editor object
55339 setEditor : function(col, editor){
55340 this.config[col].editor = editor;
55344 Roo.grid.ColumnModel.defaultRenderer = function(value){
55345 if(typeof value == "string" && value.length < 1){
55351 // Alias for backwards compatibility
55352 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55355 * Ext JS Library 1.1.1
55356 * Copyright(c) 2006-2007, Ext JS, LLC.
55358 * Originally Released Under LGPL - original licence link has changed is not relivant.
55361 * <script type="text/javascript">
55365 * @class Roo.grid.AbstractSelectionModel
55366 * @extends Roo.util.Observable
55367 * Abstract base class for grid SelectionModels. It provides the interface that should be
55368 * implemented by descendant classes. This class should not be directly instantiated.
55371 Roo.grid.AbstractSelectionModel = function(){
55372 this.locked = false;
55373 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55376 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55377 /** @ignore Called by the grid automatically. Do not call directly. */
55378 init : function(grid){
55384 * Locks the selections.
55387 this.locked = true;
55391 * Unlocks the selections.
55393 unlock : function(){
55394 this.locked = false;
55398 * Returns true if the selections are locked.
55399 * @return {Boolean}
55401 isLocked : function(){
55402 return this.locked;
55406 * Ext JS Library 1.1.1
55407 * Copyright(c) 2006-2007, Ext JS, LLC.
55409 * Originally Released Under LGPL - original licence link has changed is not relivant.
55412 * <script type="text/javascript">
55415 * @extends Roo.grid.AbstractSelectionModel
55416 * @class Roo.grid.RowSelectionModel
55417 * The default SelectionModel used by {@link Roo.grid.Grid}.
55418 * It supports multiple selections and keyboard selection/navigation.
55420 * @param {Object} config
55422 Roo.grid.RowSelectionModel = function(config){
55423 Roo.apply(this, config);
55424 this.selections = new Roo.util.MixedCollection(false, function(o){
55429 this.lastActive = false;
55433 * @event selectionchange
55434 * Fires when the selection changes
55435 * @param {SelectionModel} this
55437 "selectionchange" : true,
55439 * @event afterselectionchange
55440 * Fires after the selection changes (eg. by key press or clicking)
55441 * @param {SelectionModel} this
55443 "afterselectionchange" : true,
55445 * @event beforerowselect
55446 * Fires when a row is selected being selected, return false to cancel.
55447 * @param {SelectionModel} this
55448 * @param {Number} rowIndex The selected index
55449 * @param {Boolean} keepExisting False if other selections will be cleared
55451 "beforerowselect" : true,
55454 * Fires when a row is selected.
55455 * @param {SelectionModel} this
55456 * @param {Number} rowIndex The selected index
55457 * @param {Roo.data.Record} r The record
55459 "rowselect" : true,
55461 * @event rowdeselect
55462 * Fires when a row is deselected.
55463 * @param {SelectionModel} this
55464 * @param {Number} rowIndex The selected index
55466 "rowdeselect" : true
55468 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55469 this.locked = false;
55472 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55474 * @cfg {Boolean} singleSelect
55475 * True to allow selection of only one row at a time (defaults to false)
55477 singleSelect : false,
55480 initEvents : function(){
55482 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55483 this.grid.on("mousedown", this.handleMouseDown, this);
55484 }else{ // allow click to work like normal
55485 this.grid.on("rowclick", this.handleDragableRowClick, this);
55488 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55489 "up" : function(e){
55491 this.selectPrevious(e.shiftKey);
55492 }else if(this.last !== false && this.lastActive !== false){
55493 var last = this.last;
55494 this.selectRange(this.last, this.lastActive-1);
55495 this.grid.getView().focusRow(this.lastActive);
55496 if(last !== false){
55500 this.selectFirstRow();
55502 this.fireEvent("afterselectionchange", this);
55504 "down" : function(e){
55506 this.selectNext(e.shiftKey);
55507 }else if(this.last !== false && this.lastActive !== false){
55508 var last = this.last;
55509 this.selectRange(this.last, this.lastActive+1);
55510 this.grid.getView().focusRow(this.lastActive);
55511 if(last !== false){
55515 this.selectFirstRow();
55517 this.fireEvent("afterselectionchange", this);
55522 var view = this.grid.view;
55523 view.on("refresh", this.onRefresh, this);
55524 view.on("rowupdated", this.onRowUpdated, this);
55525 view.on("rowremoved", this.onRemove, this);
55529 onRefresh : function(){
55530 var ds = this.grid.dataSource, i, v = this.grid.view;
55531 var s = this.selections;
55532 s.each(function(r){
55533 if((i = ds.indexOfId(r.id)) != -1){
55542 onRemove : function(v, index, r){
55543 this.selections.remove(r);
55547 onRowUpdated : function(v, index, r){
55548 if(this.isSelected(r)){
55549 v.onRowSelect(index);
55555 * @param {Array} records The records to select
55556 * @param {Boolean} keepExisting (optional) True to keep existing selections
55558 selectRecords : function(records, keepExisting){
55560 this.clearSelections();
55562 var ds = this.grid.dataSource;
55563 for(var i = 0, len = records.length; i < len; i++){
55564 this.selectRow(ds.indexOf(records[i]), true);
55569 * Gets the number of selected rows.
55572 getCount : function(){
55573 return this.selections.length;
55577 * Selects the first row in the grid.
55579 selectFirstRow : function(){
55584 * Select the last row.
55585 * @param {Boolean} keepExisting (optional) True to keep existing selections
55587 selectLastRow : function(keepExisting){
55588 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55592 * Selects the row immediately following the last selected row.
55593 * @param {Boolean} keepExisting (optional) True to keep existing selections
55595 selectNext : function(keepExisting){
55596 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55597 this.selectRow(this.last+1, keepExisting);
55598 this.grid.getView().focusRow(this.last);
55603 * Selects the row that precedes the last selected row.
55604 * @param {Boolean} keepExisting (optional) True to keep existing selections
55606 selectPrevious : function(keepExisting){
55608 this.selectRow(this.last-1, keepExisting);
55609 this.grid.getView().focusRow(this.last);
55614 * Returns the selected records
55615 * @return {Array} Array of selected records
55617 getSelections : function(){
55618 return [].concat(this.selections.items);
55622 * Returns the first selected record.
55625 getSelected : function(){
55626 return this.selections.itemAt(0);
55631 * Clears all selections.
55633 clearSelections : function(fast){
55634 if(this.locked) return;
55636 var ds = this.grid.dataSource;
55637 var s = this.selections;
55638 s.each(function(r){
55639 this.deselectRow(ds.indexOfId(r.id));
55643 this.selections.clear();
55650 * Selects all rows.
55652 selectAll : function(){
55653 if(this.locked) return;
55654 this.selections.clear();
55655 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
55656 this.selectRow(i, true);
55661 * Returns True if there is a selection.
55662 * @return {Boolean}
55664 hasSelection : function(){
55665 return this.selections.length > 0;
55669 * Returns True if the specified row is selected.
55670 * @param {Number/Record} record The record or index of the record to check
55671 * @return {Boolean}
55673 isSelected : function(index){
55674 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
55675 return (r && this.selections.key(r.id) ? true : false);
55679 * Returns True if the specified record id is selected.
55680 * @param {String} id The id of record to check
55681 * @return {Boolean}
55683 isIdSelected : function(id){
55684 return (this.selections.key(id) ? true : false);
55688 handleMouseDown : function(e, t){
55689 var view = this.grid.getView(), rowIndex;
55690 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
55693 if(e.shiftKey && this.last !== false){
55694 var last = this.last;
55695 this.selectRange(last, rowIndex, e.ctrlKey);
55696 this.last = last; // reset the last
55697 view.focusRow(rowIndex);
55699 var isSelected = this.isSelected(rowIndex);
55700 if(e.button !== 0 && isSelected){
55701 view.focusRow(rowIndex);
55702 }else if(e.ctrlKey && isSelected){
55703 this.deselectRow(rowIndex);
55704 }else if(!isSelected){
55705 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
55706 view.focusRow(rowIndex);
55709 this.fireEvent("afterselectionchange", this);
55712 handleDragableRowClick : function(grid, rowIndex, e)
55714 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
55715 this.selectRow(rowIndex, false);
55716 grid.view.focusRow(rowIndex);
55717 this.fireEvent("afterselectionchange", this);
55722 * Selects multiple rows.
55723 * @param {Array} rows Array of the indexes of the row to select
55724 * @param {Boolean} keepExisting (optional) True to keep existing selections
55726 selectRows : function(rows, keepExisting){
55728 this.clearSelections();
55730 for(var i = 0, len = rows.length; i < len; i++){
55731 this.selectRow(rows[i], true);
55736 * Selects a range of rows. All rows in between startRow and endRow are also selected.
55737 * @param {Number} startRow The index of the first row in the range
55738 * @param {Number} endRow The index of the last row in the range
55739 * @param {Boolean} keepExisting (optional) True to retain existing selections
55741 selectRange : function(startRow, endRow, keepExisting){
55742 if(this.locked) return;
55744 this.clearSelections();
55746 if(startRow <= endRow){
55747 for(var i = startRow; i <= endRow; i++){
55748 this.selectRow(i, true);
55751 for(var i = startRow; i >= endRow; i--){
55752 this.selectRow(i, true);
55758 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
55759 * @param {Number} startRow The index of the first row in the range
55760 * @param {Number} endRow The index of the last row in the range
55762 deselectRange : function(startRow, endRow, preventViewNotify){
55763 if(this.locked) return;
55764 for(var i = startRow; i <= endRow; i++){
55765 this.deselectRow(i, preventViewNotify);
55771 * @param {Number} row The index of the row to select
55772 * @param {Boolean} keepExisting (optional) True to keep existing selections
55774 selectRow : function(index, keepExisting, preventViewNotify){
55775 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
55776 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
55777 if(!keepExisting || this.singleSelect){
55778 this.clearSelections();
55780 var r = this.grid.dataSource.getAt(index);
55781 this.selections.add(r);
55782 this.last = this.lastActive = index;
55783 if(!preventViewNotify){
55784 this.grid.getView().onRowSelect(index);
55786 this.fireEvent("rowselect", this, index, r);
55787 this.fireEvent("selectionchange", this);
55793 * @param {Number} row The index of the row to deselect
55795 deselectRow : function(index, preventViewNotify){
55796 if(this.locked) return;
55797 if(this.last == index){
55800 if(this.lastActive == index){
55801 this.lastActive = false;
55803 var r = this.grid.dataSource.getAt(index);
55804 this.selections.remove(r);
55805 if(!preventViewNotify){
55806 this.grid.getView().onRowDeselect(index);
55808 this.fireEvent("rowdeselect", this, index);
55809 this.fireEvent("selectionchange", this);
55813 restoreLast : function(){
55815 this.last = this._last;
55820 acceptsNav : function(row, col, cm){
55821 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55825 onEditorKey : function(field, e){
55826 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
55831 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55833 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55835 }else if(k == e.ENTER && !e.ctrlKey){
55839 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
55841 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
55843 }else if(k == e.ESC){
55847 g.startEditing(newCell[0], newCell[1]);
55852 * Ext JS Library 1.1.1
55853 * Copyright(c) 2006-2007, Ext JS, LLC.
55855 * Originally Released Under LGPL - original licence link has changed is not relivant.
55858 * <script type="text/javascript">
55861 * @class Roo.grid.CellSelectionModel
55862 * @extends Roo.grid.AbstractSelectionModel
55863 * This class provides the basic implementation for cell selection in a grid.
55865 * @param {Object} config The object containing the configuration of this model.
55866 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
55868 Roo.grid.CellSelectionModel = function(config){
55869 Roo.apply(this, config);
55871 this.selection = null;
55875 * @event beforerowselect
55876 * Fires before a cell is selected.
55877 * @param {SelectionModel} this
55878 * @param {Number} rowIndex The selected row index
55879 * @param {Number} colIndex The selected cell index
55881 "beforecellselect" : true,
55883 * @event cellselect
55884 * Fires when a cell is selected.
55885 * @param {SelectionModel} this
55886 * @param {Number} rowIndex The selected row index
55887 * @param {Number} colIndex The selected cell index
55889 "cellselect" : true,
55891 * @event selectionchange
55892 * Fires when the active selection changes.
55893 * @param {SelectionModel} this
55894 * @param {Object} selection null for no selection or an object (o) with two properties
55896 <li>o.record: the record object for the row the selection is in</li>
55897 <li>o.cell: An array of [rowIndex, columnIndex]</li>
55900 "selectionchange" : true,
55903 * Fires when the tab (or enter) was pressed on the last editable cell
55904 * You can use this to trigger add new row.
55905 * @param {SelectionModel} this
55909 * @event beforeeditnext
55910 * Fires before the next editable sell is made active
55911 * You can use this to skip to another cell or fire the tabend
55912 * if you set cell to false
55913 * @param {Object} eventdata object : { cell : [ row, col ] }
55915 "beforeeditnext" : true
55917 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
55920 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
55922 enter_is_tab: false,
55925 initEvents : function(){
55926 this.grid.on("mousedown", this.handleMouseDown, this);
55927 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
55928 var view = this.grid.view;
55929 view.on("refresh", this.onViewChange, this);
55930 view.on("rowupdated", this.onRowUpdated, this);
55931 view.on("beforerowremoved", this.clearSelections, this);
55932 view.on("beforerowsinserted", this.clearSelections, this);
55933 if(this.grid.isEditor){
55934 this.grid.on("beforeedit", this.beforeEdit, this);
55939 beforeEdit : function(e){
55940 this.select(e.row, e.column, false, true, e.record);
55944 onRowUpdated : function(v, index, r){
55945 if(this.selection && this.selection.record == r){
55946 v.onCellSelect(index, this.selection.cell[1]);
55951 onViewChange : function(){
55952 this.clearSelections(true);
55956 * Returns the currently selected cell,.
55957 * @return {Array} The selected cell (row, column) or null if none selected.
55959 getSelectedCell : function(){
55960 return this.selection ? this.selection.cell : null;
55964 * Clears all selections.
55965 * @param {Boolean} true to prevent the gridview from being notified about the change.
55967 clearSelections : function(preventNotify){
55968 var s = this.selection;
55970 if(preventNotify !== true){
55971 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
55973 this.selection = null;
55974 this.fireEvent("selectionchange", this, null);
55979 * Returns true if there is a selection.
55980 * @return {Boolean}
55982 hasSelection : function(){
55983 return this.selection ? true : false;
55987 handleMouseDown : function(e, t){
55988 var v = this.grid.getView();
55989 if(this.isLocked()){
55992 var row = v.findRowIndex(t);
55993 var cell = v.findCellIndex(t);
55994 if(row !== false && cell !== false){
55995 this.select(row, cell);
56001 * @param {Number} rowIndex
56002 * @param {Number} collIndex
56004 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
56005 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
56006 this.clearSelections();
56007 r = r || this.grid.dataSource.getAt(rowIndex);
56010 cell : [rowIndex, colIndex]
56012 if(!preventViewNotify){
56013 var v = this.grid.getView();
56014 v.onCellSelect(rowIndex, colIndex);
56015 if(preventFocus !== true){
56016 v.focusCell(rowIndex, colIndex);
56019 this.fireEvent("cellselect", this, rowIndex, colIndex);
56020 this.fireEvent("selectionchange", this, this.selection);
56025 isSelectable : function(rowIndex, colIndex, cm){
56026 return !cm.isHidden(colIndex);
56030 handleKeyDown : function(e){
56031 //Roo.log('Cell Sel Model handleKeyDown');
56032 if(!e.isNavKeyPress()){
56035 var g = this.grid, s = this.selection;
56038 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
56040 this.select(cell[0], cell[1]);
56045 var walk = function(row, col, step){
56046 return g.walkCells(row, col, step, sm.isSelectable, sm);
56048 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
56055 // handled by onEditorKey
56056 if (g.isEditor && g.editing) {
56060 newCell = walk(r, c-1, -1);
56062 newCell = walk(r, c+1, 1);
56067 newCell = walk(r+1, c, 1);
56071 newCell = walk(r-1, c, -1);
56075 newCell = walk(r, c+1, 1);
56079 newCell = walk(r, c-1, -1);
56084 if(g.isEditor && !g.editing){
56085 g.startEditing(r, c);
56094 this.select(newCell[0], newCell[1]);
56100 acceptsNav : function(row, col, cm){
56101 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56105 * @param {Number} field (not used) - as it's normally used as a listener
56106 * @param {Number} e - event - fake it by using
56108 * var e = Roo.EventObjectImpl.prototype;
56109 * e.keyCode = e.TAB
56113 onEditorKey : function(field, e){
56115 var k = e.getKey(),
56118 ed = g.activeEditor,
56120 ///Roo.log('onEditorKey' + k);
56123 if (this.enter_is_tab && k == e.ENTER) {
56129 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56131 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56137 } else if(k == e.ENTER && !e.ctrlKey){
56140 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56142 } else if(k == e.ESC){
56147 var ecall = { cell : newCell, forward : forward };
56148 this.fireEvent('beforeeditnext', ecall );
56149 newCell = ecall.cell;
56150 forward = ecall.forward;
56154 //Roo.log('next cell after edit');
56155 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
56156 } else if (forward) {
56157 // tabbed past last
56158 this.fireEvent.defer(100, this, ['tabend',this]);
56163 * Ext JS Library 1.1.1
56164 * Copyright(c) 2006-2007, Ext JS, LLC.
56166 * Originally Released Under LGPL - original licence link has changed is not relivant.
56169 * <script type="text/javascript">
56173 * @class Roo.grid.EditorGrid
56174 * @extends Roo.grid.Grid
56175 * Class for creating and editable grid.
56176 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56177 * The container MUST have some type of size defined for the grid to fill. The container will be
56178 * automatically set to position relative if it isn't already.
56179 * @param {Object} dataSource The data model to bind to
56180 * @param {Object} colModel The column model with info about this grid's columns
56182 Roo.grid.EditorGrid = function(container, config){
56183 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56184 this.getGridEl().addClass("xedit-grid");
56186 if(!this.selModel){
56187 this.selModel = new Roo.grid.CellSelectionModel();
56190 this.activeEditor = null;
56194 * @event beforeedit
56195 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56196 * <ul style="padding:5px;padding-left:16px;">
56197 * <li>grid - This grid</li>
56198 * <li>record - The record being edited</li>
56199 * <li>field - The field name being edited</li>
56200 * <li>value - The value for the field being edited.</li>
56201 * <li>row - The grid row index</li>
56202 * <li>column - The grid column index</li>
56203 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56205 * @param {Object} e An edit event (see above for description)
56207 "beforeedit" : true,
56210 * Fires after a cell is edited. <br />
56211 * <ul style="padding:5px;padding-left:16px;">
56212 * <li>grid - This grid</li>
56213 * <li>record - The record being edited</li>
56214 * <li>field - The field name being edited</li>
56215 * <li>value - The value being set</li>
56216 * <li>originalValue - The original value for the field, before the edit.</li>
56217 * <li>row - The grid row index</li>
56218 * <li>column - The grid column index</li>
56220 * @param {Object} e An edit event (see above for description)
56222 "afteredit" : true,
56224 * @event validateedit
56225 * Fires after a cell is edited, but before the value is set in the record.
56226 * You can use this to modify the value being set in the field, Return false
56227 * to cancel the change. The edit event object has the following properties <br />
56228 * <ul style="padding:5px;padding-left:16px;">
56229 * <li>editor - This editor</li>
56230 * <li>grid - This grid</li>
56231 * <li>record - The record being edited</li>
56232 * <li>field - The field name being edited</li>
56233 * <li>value - The value being set</li>
56234 * <li>originalValue - The original value for the field, before the edit.</li>
56235 * <li>row - The grid row index</li>
56236 * <li>column - The grid column index</li>
56237 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56239 * @param {Object} e An edit event (see above for description)
56241 "validateedit" : true
56243 this.on("bodyscroll", this.stopEditing, this);
56244 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56247 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56249 * @cfg {Number} clicksToEdit
56250 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56257 trackMouseOver: false, // causes very odd FF errors
56259 onCellDblClick : function(g, row, col){
56260 this.startEditing(row, col);
56263 onEditComplete : function(ed, value, startValue){
56264 this.editing = false;
56265 this.activeEditor = null;
56266 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56268 var field = this.colModel.getDataIndex(ed.col);
56273 originalValue: startValue,
56280 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56283 if(String(value) !== String(startValue)){
56285 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56286 r.set(field, e.value);
56287 // if we are dealing with a combo box..
56288 // then we also set the 'name' colum to be the displayField
56289 if (ed.field.displayField && ed.field.name) {
56290 r.set(ed.field.name, ed.field.el.dom.value);
56293 delete e.cancel; //?? why!!!
56294 this.fireEvent("afteredit", e);
56297 this.fireEvent("afteredit", e); // always fire it!
56299 this.view.focusCell(ed.row, ed.col);
56303 * Starts editing the specified for the specified row/column
56304 * @param {Number} rowIndex
56305 * @param {Number} colIndex
56307 startEditing : function(row, col){
56308 this.stopEditing();
56309 if(this.colModel.isCellEditable(col, row)){
56310 this.view.ensureVisible(row, col, true);
56312 var r = this.dataSource.getAt(row);
56313 var field = this.colModel.getDataIndex(col);
56314 var cell = Roo.get(this.view.getCell(row,col));
56319 value: r.data[field],
56324 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56325 this.editing = true;
56326 var ed = this.colModel.getCellEditor(col, row);
56332 ed.render(ed.parentEl || document.body);
56338 (function(){ // complex but required for focus issues in safari, ie and opera
56342 ed.on("complete", this.onEditComplete, this, {single: true});
56343 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56344 this.activeEditor = ed;
56345 var v = r.data[field];
56346 ed.startEdit(this.view.getCell(row, col), v);
56347 // combo's with 'displayField and name set
56348 if (ed.field.displayField && ed.field.name) {
56349 ed.field.el.dom.value = r.data[ed.field.name];
56353 }).defer(50, this);
56359 * Stops any active editing
56361 stopEditing : function(){
56362 if(this.activeEditor){
56363 this.activeEditor.completeEdit();
56365 this.activeEditor = null;
56369 * Called to get grid's drag proxy text, by default returns this.ddText.
56372 getDragDropText : function(){
56373 var count = this.selModel.getSelectedCell() ? 1 : 0;
56374 return String.format(this.ddText, count, count == 1 ? '' : 's');
56379 * Ext JS Library 1.1.1
56380 * Copyright(c) 2006-2007, Ext JS, LLC.
56382 * Originally Released Under LGPL - original licence link has changed is not relivant.
56385 * <script type="text/javascript">
56388 // private - not really -- you end up using it !
56389 // This is a support class used internally by the Grid components
56392 * @class Roo.grid.GridEditor
56393 * @extends Roo.Editor
56394 * Class for creating and editable grid elements.
56395 * @param {Object} config any settings (must include field)
56397 Roo.grid.GridEditor = function(field, config){
56398 if (!config && field.field) {
56400 field = Roo.factory(config.field, Roo.form);
56402 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56403 field.monitorTab = false;
56406 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56409 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56412 alignment: "tl-tl",
56415 cls: "x-small-editor x-grid-editor",
56420 * Ext JS Library 1.1.1
56421 * Copyright(c) 2006-2007, Ext JS, LLC.
56423 * Originally Released Under LGPL - original licence link has changed is not relivant.
56426 * <script type="text/javascript">
56431 Roo.grid.PropertyRecord = Roo.data.Record.create([
56432 {name:'name',type:'string'}, 'value'
56436 Roo.grid.PropertyStore = function(grid, source){
56438 this.store = new Roo.data.Store({
56439 recordType : Roo.grid.PropertyRecord
56441 this.store.on('update', this.onUpdate, this);
56443 this.setSource(source);
56445 Roo.grid.PropertyStore.superclass.constructor.call(this);
56450 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56451 setSource : function(o){
56453 this.store.removeAll();
56456 if(this.isEditableValue(o[k])){
56457 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56460 this.store.loadRecords({records: data}, {}, true);
56463 onUpdate : function(ds, record, type){
56464 if(type == Roo.data.Record.EDIT){
56465 var v = record.data['value'];
56466 var oldValue = record.modified['value'];
56467 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56468 this.source[record.id] = v;
56470 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56477 getProperty : function(row){
56478 return this.store.getAt(row);
56481 isEditableValue: function(val){
56482 if(val && val instanceof Date){
56484 }else if(typeof val == 'object' || typeof val == 'function'){
56490 setValue : function(prop, value){
56491 this.source[prop] = value;
56492 this.store.getById(prop).set('value', value);
56495 getSource : function(){
56496 return this.source;
56500 Roo.grid.PropertyColumnModel = function(grid, store){
56503 g.PropertyColumnModel.superclass.constructor.call(this, [
56504 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56505 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56507 this.store = store;
56508 this.bselect = Roo.DomHelper.append(document.body, {
56509 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56510 {tag: 'option', value: 'true', html: 'true'},
56511 {tag: 'option', value: 'false', html: 'false'}
56514 Roo.id(this.bselect);
56517 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56518 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56519 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56520 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56521 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56523 this.renderCellDelegate = this.renderCell.createDelegate(this);
56524 this.renderPropDelegate = this.renderProp.createDelegate(this);
56527 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56531 valueText : 'Value',
56533 dateFormat : 'm/j/Y',
56536 renderDate : function(dateVal){
56537 return dateVal.dateFormat(this.dateFormat);
56540 renderBool : function(bVal){
56541 return bVal ? 'true' : 'false';
56544 isCellEditable : function(colIndex, rowIndex){
56545 return colIndex == 1;
56548 getRenderer : function(col){
56550 this.renderCellDelegate : this.renderPropDelegate;
56553 renderProp : function(v){
56554 return this.getPropertyName(v);
56557 renderCell : function(val){
56559 if(val instanceof Date){
56560 rv = this.renderDate(val);
56561 }else if(typeof val == 'boolean'){
56562 rv = this.renderBool(val);
56564 return Roo.util.Format.htmlEncode(rv);
56567 getPropertyName : function(name){
56568 var pn = this.grid.propertyNames;
56569 return pn && pn[name] ? pn[name] : name;
56572 getCellEditor : function(colIndex, rowIndex){
56573 var p = this.store.getProperty(rowIndex);
56574 var n = p.data['name'], val = p.data['value'];
56576 if(typeof(this.grid.customEditors[n]) == 'string'){
56577 return this.editors[this.grid.customEditors[n]];
56579 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56580 return this.grid.customEditors[n];
56582 if(val instanceof Date){
56583 return this.editors['date'];
56584 }else if(typeof val == 'number'){
56585 return this.editors['number'];
56586 }else if(typeof val == 'boolean'){
56587 return this.editors['boolean'];
56589 return this.editors['string'];
56595 * @class Roo.grid.PropertyGrid
56596 * @extends Roo.grid.EditorGrid
56597 * This class represents the interface of a component based property grid control.
56598 * <br><br>Usage:<pre><code>
56599 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56607 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56608 * The container MUST have some type of size defined for the grid to fill. The container will be
56609 * automatically set to position relative if it isn't already.
56610 * @param {Object} config A config object that sets properties on this grid.
56612 Roo.grid.PropertyGrid = function(container, config){
56613 config = config || {};
56614 var store = new Roo.grid.PropertyStore(this);
56615 this.store = store;
56616 var cm = new Roo.grid.PropertyColumnModel(this, store);
56617 store.store.sort('name', 'ASC');
56618 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
56621 enableColLock:false,
56622 enableColumnMove:false,
56624 trackMouseOver: false,
56627 this.getGridEl().addClass('x-props-grid');
56628 this.lastEditRow = null;
56629 this.on('columnresize', this.onColumnResize, this);
56632 * @event beforepropertychange
56633 * Fires before a property changes (return false to stop?)
56634 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56635 * @param {String} id Record Id
56636 * @param {String} newval New Value
56637 * @param {String} oldval Old Value
56639 "beforepropertychange": true,
56641 * @event propertychange
56642 * Fires after a property changes
56643 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56644 * @param {String} id Record Id
56645 * @param {String} newval New Value
56646 * @param {String} oldval Old Value
56648 "propertychange": true
56650 this.customEditors = this.customEditors || {};
56652 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
56655 * @cfg {Object} customEditors map of colnames=> custom editors.
56656 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
56657 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
56658 * false disables editing of the field.
56662 * @cfg {Object} propertyNames map of property Names to their displayed value
56665 render : function(){
56666 Roo.grid.PropertyGrid.superclass.render.call(this);
56667 this.autoSize.defer(100, this);
56670 autoSize : function(){
56671 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
56673 this.view.fitColumns();
56677 onColumnResize : function(){
56678 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
56682 * Sets the data for the Grid
56683 * accepts a Key => Value object of all the elements avaiable.
56684 * @param {Object} data to appear in grid.
56686 setSource : function(source){
56687 this.store.setSource(source);
56691 * Gets all the data from the grid.
56692 * @return {Object} data data stored in grid
56694 getSource : function(){
56695 return this.store.getSource();
56704 * @class Roo.grid.Calendar
56705 * @extends Roo.util.Grid
56706 * This class extends the Grid to provide a calendar widget
56707 * <br><br>Usage:<pre><code>
56708 var grid = new Roo.grid.Calendar("my-container-id", {
56711 selModel: mySelectionModel,
56712 autoSizeColumns: true,
56713 monitorWindowResize: false,
56714 trackMouseOver: true
56715 eventstore : real data store..
56721 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56722 * The container MUST have some type of size defined for the grid to fill. The container will be
56723 * automatically set to position relative if it isn't already.
56724 * @param {Object} config A config object that sets properties on this grid.
56726 Roo.grid.Calendar = function(container, config){
56727 // initialize the container
56728 this.container = Roo.get(container);
56729 this.container.update("");
56730 this.container.setStyle("overflow", "hidden");
56731 this.container.addClass('x-grid-container');
56733 this.id = this.container.id;
56735 Roo.apply(this, config);
56736 // check and correct shorthanded configs
56740 for (var r = 0;r < 6;r++) {
56743 for (var c =0;c < 7;c++) {
56747 if (this.eventStore) {
56748 this.eventStore= Roo.factory(this.eventStore, Roo.data);
56749 this.eventStore.on('load',this.onLoad, this);
56750 this.eventStore.on('beforeload',this.clearEvents, this);
56754 this.dataSource = new Roo.data.Store({
56755 proxy: new Roo.data.MemoryProxy(rows),
56756 reader: new Roo.data.ArrayReader({}, [
56757 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
56760 this.dataSource.load();
56761 this.ds = this.dataSource;
56762 this.ds.xmodule = this.xmodule || false;
56765 var cellRender = function(v,x,r)
56767 return String.format(
56768 '<div class="fc-day fc-widget-content"><div>' +
56769 '<div class="fc-event-container"></div>' +
56770 '<div class="fc-day-number">{0}</div>'+
56772 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
56773 '</div></div>', v);
56778 this.colModel = new Roo.grid.ColumnModel( [
56780 xtype: 'ColumnModel',
56782 dataIndex : 'weekday0',
56784 renderer : cellRender
56787 xtype: 'ColumnModel',
56789 dataIndex : 'weekday1',
56791 renderer : cellRender
56794 xtype: 'ColumnModel',
56796 dataIndex : 'weekday2',
56797 header : 'Tuesday',
56798 renderer : cellRender
56801 xtype: 'ColumnModel',
56803 dataIndex : 'weekday3',
56804 header : 'Wednesday',
56805 renderer : cellRender
56808 xtype: 'ColumnModel',
56810 dataIndex : 'weekday4',
56811 header : 'Thursday',
56812 renderer : cellRender
56815 xtype: 'ColumnModel',
56817 dataIndex : 'weekday5',
56819 renderer : cellRender
56822 xtype: 'ColumnModel',
56824 dataIndex : 'weekday6',
56825 header : 'Saturday',
56826 renderer : cellRender
56829 this.cm = this.colModel;
56830 this.cm.xmodule = this.xmodule || false;
56834 //this.selModel = new Roo.grid.CellSelectionModel();
56835 //this.sm = this.selModel;
56836 //this.selModel.init(this);
56840 this.container.setWidth(this.width);
56844 this.container.setHeight(this.height);
56851 * The raw click event for the entire grid.
56852 * @param {Roo.EventObject} e
56857 * The raw dblclick event for the entire grid.
56858 * @param {Roo.EventObject} e
56862 * @event contextmenu
56863 * The raw contextmenu event for the entire grid.
56864 * @param {Roo.EventObject} e
56866 "contextmenu" : true,
56869 * The raw mousedown event for the entire grid.
56870 * @param {Roo.EventObject} e
56872 "mousedown" : true,
56875 * The raw mouseup event for the entire grid.
56876 * @param {Roo.EventObject} e
56881 * The raw mouseover event for the entire grid.
56882 * @param {Roo.EventObject} e
56884 "mouseover" : true,
56887 * The raw mouseout event for the entire grid.
56888 * @param {Roo.EventObject} e
56893 * The raw keypress event for the entire grid.
56894 * @param {Roo.EventObject} e
56899 * The raw keydown event for the entire grid.
56900 * @param {Roo.EventObject} e
56908 * Fires when a cell is clicked
56909 * @param {Grid} this
56910 * @param {Number} rowIndex
56911 * @param {Number} columnIndex
56912 * @param {Roo.EventObject} e
56914 "cellclick" : true,
56916 * @event celldblclick
56917 * Fires when a cell is double clicked
56918 * @param {Grid} this
56919 * @param {Number} rowIndex
56920 * @param {Number} columnIndex
56921 * @param {Roo.EventObject} e
56923 "celldblclick" : true,
56926 * Fires when a row is clicked
56927 * @param {Grid} this
56928 * @param {Number} rowIndex
56929 * @param {Roo.EventObject} e
56933 * @event rowdblclick
56934 * Fires when a row is double clicked
56935 * @param {Grid} this
56936 * @param {Number} rowIndex
56937 * @param {Roo.EventObject} e
56939 "rowdblclick" : true,
56941 * @event headerclick
56942 * Fires when a header is clicked
56943 * @param {Grid} this
56944 * @param {Number} columnIndex
56945 * @param {Roo.EventObject} e
56947 "headerclick" : true,
56949 * @event headerdblclick
56950 * Fires when a header cell is double clicked
56951 * @param {Grid} this
56952 * @param {Number} columnIndex
56953 * @param {Roo.EventObject} e
56955 "headerdblclick" : true,
56957 * @event rowcontextmenu
56958 * Fires when a row is right clicked
56959 * @param {Grid} this
56960 * @param {Number} rowIndex
56961 * @param {Roo.EventObject} e
56963 "rowcontextmenu" : true,
56965 * @event cellcontextmenu
56966 * Fires when a cell is right clicked
56967 * @param {Grid} this
56968 * @param {Number} rowIndex
56969 * @param {Number} cellIndex
56970 * @param {Roo.EventObject} e
56972 "cellcontextmenu" : true,
56974 * @event headercontextmenu
56975 * Fires when a header is right clicked
56976 * @param {Grid} this
56977 * @param {Number} columnIndex
56978 * @param {Roo.EventObject} e
56980 "headercontextmenu" : true,
56982 * @event bodyscroll
56983 * Fires when the body element is scrolled
56984 * @param {Number} scrollLeft
56985 * @param {Number} scrollTop
56987 "bodyscroll" : true,
56989 * @event columnresize
56990 * Fires when the user resizes a column
56991 * @param {Number} columnIndex
56992 * @param {Number} newSize
56994 "columnresize" : true,
56996 * @event columnmove
56997 * Fires when the user moves a column
56998 * @param {Number} oldIndex
56999 * @param {Number} newIndex
57001 "columnmove" : true,
57004 * Fires when row(s) start being dragged
57005 * @param {Grid} this
57006 * @param {Roo.GridDD} dd The drag drop object
57007 * @param {event} e The raw browser event
57009 "startdrag" : true,
57012 * Fires when a drag operation is complete
57013 * @param {Grid} this
57014 * @param {Roo.GridDD} dd The drag drop object
57015 * @param {event} e The raw browser event
57020 * Fires when dragged row(s) are dropped on a valid DD target
57021 * @param {Grid} this
57022 * @param {Roo.GridDD} dd The drag drop object
57023 * @param {String} targetId The target drag drop object
57024 * @param {event} e The raw browser event
57029 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57030 * @param {Grid} this
57031 * @param {Roo.GridDD} dd The drag drop object
57032 * @param {String} targetId The target drag drop object
57033 * @param {event} e The raw browser event
57038 * Fires when the dragged row(s) first cross another DD target while being dragged
57039 * @param {Grid} this
57040 * @param {Roo.GridDD} dd The drag drop object
57041 * @param {String} targetId The target drag drop object
57042 * @param {event} e The raw browser event
57044 "dragenter" : true,
57047 * Fires when the dragged row(s) leave another DD target while being dragged
57048 * @param {Grid} this
57049 * @param {Roo.GridDD} dd The drag drop object
57050 * @param {String} targetId The target drag drop object
57051 * @param {event} e The raw browser event
57056 * Fires when a row is rendered, so you can change add a style to it.
57057 * @param {GridView} gridview The grid view
57058 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57064 * Fires when the grid is rendered
57065 * @param {Grid} grid
57070 * Fires when a date is selected
57071 * @param {DatePicker} this
57072 * @param {Date} date The selected date
57076 * @event monthchange
57077 * Fires when the displayed month changes
57078 * @param {DatePicker} this
57079 * @param {Date} date The selected month
57081 'monthchange': true,
57083 * @event evententer
57084 * Fires when mouse over an event
57085 * @param {Calendar} this
57086 * @param {event} Event
57088 'evententer': true,
57090 * @event eventleave
57091 * Fires when the mouse leaves an
57092 * @param {Calendar} this
57095 'eventleave': true,
57097 * @event eventclick
57098 * Fires when the mouse click an
57099 * @param {Calendar} this
57102 'eventclick': true,
57104 * @event eventrender
57105 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
57106 * @param {Calendar} this
57107 * @param {data} data to be modified
57109 'eventrender': true
57113 Roo.grid.Grid.superclass.constructor.call(this);
57114 this.on('render', function() {
57115 this.view.el.addClass('x-grid-cal');
57117 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
57121 if (!Roo.grid.Calendar.style) {
57122 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
57125 '.x-grid-cal .x-grid-col' : {
57126 height: 'auto !important',
57127 'vertical-align': 'top'
57129 '.x-grid-cal .fc-event-hori' : {
57140 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
57142 * @cfg {Store} eventStore The store that loads events.
57147 activeDate : false,
57150 monitorWindowResize : false,
57153 resizeColumns : function() {
57154 var col = (this.view.el.getWidth() / 7) - 3;
57155 // loop through cols, and setWidth
57156 for(var i =0 ; i < 7 ; i++){
57157 this.cm.setColumnWidth(i, col);
57160 setDate :function(date) {
57162 Roo.log('setDate?');
57164 this.resizeColumns();
57165 var vd = this.activeDate;
57166 this.activeDate = date;
57167 // if(vd && this.el){
57168 // var t = date.getTime();
57169 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57170 // Roo.log('using add remove');
57172 // this.fireEvent('monthchange', this, date);
57174 // this.cells.removeClass("fc-state-highlight");
57175 // this.cells.each(function(c){
57176 // if(c.dateValue == t){
57177 // c.addClass("fc-state-highlight");
57178 // setTimeout(function(){
57179 // try{c.dom.firstChild.focus();}catch(e){}
57189 var days = date.getDaysInMonth();
57191 var firstOfMonth = date.getFirstDateOfMonth();
57192 var startingPos = firstOfMonth.getDay()-this.startDay;
57194 if(startingPos < this.startDay){
57198 var pm = date.add(Date.MONTH, -1);
57199 var prevStart = pm.getDaysInMonth()-startingPos;
57203 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57205 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57206 //this.cells.addClassOnOver('fc-state-hover');
57208 var cells = this.cells.elements;
57209 var textEls = this.textNodes;
57211 //Roo.each(cells, function(cell){
57212 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57215 days += startingPos;
57217 // convert everything to numbers so it's fast
57218 var day = 86400000;
57219 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57222 //Roo.log(prevStart);
57224 var today = new Date().clearTime().getTime();
57225 var sel = date.clearTime().getTime();
57226 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57227 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57228 var ddMatch = this.disabledDatesRE;
57229 var ddText = this.disabledDatesText;
57230 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57231 var ddaysText = this.disabledDaysText;
57232 var format = this.format;
57234 var setCellClass = function(cal, cell){
57236 //Roo.log('set Cell Class');
57238 var t = d.getTime();
57243 cell.dateValue = t;
57245 cell.className += " fc-today";
57246 cell.className += " fc-state-highlight";
57247 cell.title = cal.todayText;
57250 // disable highlight in other month..
57251 cell.className += " fc-state-highlight";
57256 //cell.className = " fc-state-disabled";
57257 cell.title = cal.minText;
57261 //cell.className = " fc-state-disabled";
57262 cell.title = cal.maxText;
57266 if(ddays.indexOf(d.getDay()) != -1){
57267 // cell.title = ddaysText;
57268 // cell.className = " fc-state-disabled";
57271 if(ddMatch && format){
57272 var fvalue = d.dateFormat(format);
57273 if(ddMatch.test(fvalue)){
57274 cell.title = ddText.replace("%0", fvalue);
57275 cell.className = " fc-state-disabled";
57279 if (!cell.initialClassName) {
57280 cell.initialClassName = cell.dom.className;
57283 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57288 for(; i < startingPos; i++) {
57289 cells[i].dayName = (++prevStart);
57290 Roo.log(textEls[i]);
57291 d.setDate(d.getDate()+1);
57293 //cells[i].className = "fc-past fc-other-month";
57294 setCellClass(this, cells[i]);
57299 for(; i < days; i++){
57300 intDay = i - startingPos + 1;
57301 cells[i].dayName = (intDay);
57302 d.setDate(d.getDate()+1);
57304 cells[i].className = ''; // "x-date-active";
57305 setCellClass(this, cells[i]);
57309 for(; i < 42; i++) {
57310 //textEls[i].innerHTML = (++extraDays);
57312 d.setDate(d.getDate()+1);
57313 cells[i].dayName = (++extraDays);
57314 cells[i].className = "fc-future fc-other-month";
57315 setCellClass(this, cells[i]);
57318 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57320 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57322 // this will cause all the cells to mis
57325 for (var r = 0;r < 6;r++) {
57326 for (var c =0;c < 7;c++) {
57327 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57331 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57332 for(i=0;i<cells.length;i++) {
57334 this.cells.elements[i].dayName = cells[i].dayName ;
57335 this.cells.elements[i].className = cells[i].className;
57336 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57337 this.cells.elements[i].title = cells[i].title ;
57338 this.cells.elements[i].dateValue = cells[i].dateValue ;
57344 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57345 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57347 ////if(totalRows != 6){
57348 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57349 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57352 this.fireEvent('monthchange', this, date);
57357 * Returns the grid's SelectionModel.
57358 * @return {SelectionModel}
57360 getSelectionModel : function(){
57361 if(!this.selModel){
57362 this.selModel = new Roo.grid.CellSelectionModel();
57364 return this.selModel;
57368 this.eventStore.load()
57374 findCell : function(dt) {
57375 dt = dt.clearTime().getTime();
57377 this.cells.each(function(c){
57378 //Roo.log("check " +c.dateValue + '?=' + dt);
57379 if(c.dateValue == dt){
57389 findCells : function(rec) {
57390 var s = rec.data.start_dt.clone().clearTime().getTime();
57392 var e= rec.data.end_dt.clone().clearTime().getTime();
57395 this.cells.each(function(c){
57396 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57398 if(c.dateValue > e){
57401 if(c.dateValue < s){
57410 findBestRow: function(cells)
57414 for (var i =0 ; i < cells.length;i++) {
57415 ret = Math.max(cells[i].rows || 0,ret);
57422 addItem : function(rec)
57424 // look for vertical location slot in
57425 var cells = this.findCells(rec);
57427 rec.row = this.findBestRow(cells);
57429 // work out the location.
57433 for(var i =0; i < cells.length; i++) {
57441 if (crow.start.getY() == cells[i].getY()) {
57443 crow.end = cells[i];
57459 for (var i = 0; i < cells.length;i++) {
57460 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57467 clearEvents: function() {
57469 if (!this.eventStore.getCount()) {
57472 // reset number of rows in cells.
57473 Roo.each(this.cells.elements, function(c){
57477 this.eventStore.each(function(e) {
57478 this.clearEvent(e);
57483 clearEvent : function(ev)
57486 Roo.each(ev.els, function(el) {
57487 el.un('mouseenter' ,this.onEventEnter, this);
57488 el.un('mouseleave' ,this.onEventLeave, this);
57496 renderEvent : function(ev,ctr) {
57498 ctr = this.view.el.select('.fc-event-container',true).first();
57502 this.clearEvent(ev);
57508 var cells = ev.cells;
57509 var rows = ev.rows;
57510 this.fireEvent('eventrender', this, ev);
57512 for(var i =0; i < rows.length; i++) {
57516 cls += ' fc-event-start';
57518 if ((i+1) == rows.length) {
57519 cls += ' fc-event-end';
57522 //Roo.log(ev.data);
57523 // how many rows should it span..
57524 var cg = this.eventTmpl.append(ctr,Roo.apply({
57527 }, ev.data) , true);
57530 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57531 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57532 cg.on('click', this.onEventClick, this, ev);
57536 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57537 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57540 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57541 cg.setWidth(ebox.right - sbox.x -2);
57545 renderEvents: function()
57547 // first make sure there is enough space..
57549 if (!this.eventTmpl) {
57550 this.eventTmpl = new Roo.Template(
57551 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57552 '<div class="fc-event-inner">' +
57553 '<span class="fc-event-time">{time}</span>' +
57554 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57556 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57564 this.cells.each(function(c) {
57565 //Roo.log(c.select('.fc-day-content div',true).first());
57566 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57569 var ctr = this.view.el.select('.fc-event-container',true).first();
57572 this.eventStore.each(function(ev){
57574 this.renderEvent(ev);
57578 this.view.layout();
57582 onEventEnter: function (e, el,event,d) {
57583 this.fireEvent('evententer', this, el, event);
57586 onEventLeave: function (e, el,event,d) {
57587 this.fireEvent('eventleave', this, el, event);
57590 onEventClick: function (e, el,event,d) {
57591 this.fireEvent('eventclick', this, el, event);
57594 onMonthChange: function () {
57598 onLoad: function () {
57600 //Roo.log('calendar onload');
57602 if(this.eventStore.getCount() > 0){
57606 this.eventStore.each(function(d){
57611 if (typeof(add.end_dt) == 'undefined') {
57612 Roo.log("Missing End time in calendar data: ");
57616 if (typeof(add.start_dt) == 'undefined') {
57617 Roo.log("Missing Start time in calendar data: ");
57621 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
57622 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
57623 add.id = add.id || d.id;
57624 add.title = add.title || '??';
57632 this.renderEvents();
57642 render : function ()
57646 if (!this.view.el.hasClass('course-timesheet')) {
57647 this.view.el.addClass('course-timesheet');
57649 if (this.tsStyle) {
57654 Roo.log(_this.grid.view.el.getWidth());
57657 this.tsStyle = Roo.util.CSS.createStyleSheet({
57658 '.course-timesheet .x-grid-row' : {
57661 '.x-grid-row td' : {
57662 'vertical-align' : 0
57664 '.course-edit-link' : {
57666 'text-overflow' : 'ellipsis',
57667 'overflow' : 'hidden',
57668 'white-space' : 'nowrap',
57669 'cursor' : 'pointer'
57674 '.de-act-sup-link' : {
57675 'color' : 'purple',
57676 'text-decoration' : 'line-through'
57680 'text-decoration' : 'line-through'
57682 '.course-timesheet .course-highlight' : {
57683 'border-top-style': 'dashed !important',
57684 'border-bottom-bottom': 'dashed !important'
57686 '.course-timesheet .course-item' : {
57687 'font-family' : 'tahoma, arial, helvetica',
57688 'font-size' : '11px',
57689 'overflow' : 'hidden',
57690 'padding-left' : '10px',
57691 'padding-right' : '10px',
57692 'padding-top' : '10px'
57700 monitorWindowResize : false,
57701 cellrenderer : function(v,x,r)
57706 xtype: 'CellSelectionModel',
57713 beforeload : function (_self, options)
57715 options.params = options.params || {};
57716 options.params._month = _this.monthField.getValue();
57717 options.params.limit = 9999;
57718 options.params['sort'] = 'when_dt';
57719 options.params['dir'] = 'ASC';
57720 this.proxy.loadResponse = this.loadResponse;
57722 //this.addColumns();
57724 load : function (_self, records, options)
57726 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
57727 // if you click on the translation.. you can edit it...
57728 var el = Roo.get(this);
57729 var id = el.dom.getAttribute('data-id');
57730 var d = el.dom.getAttribute('data-date');
57731 var t = el.dom.getAttribute('data-time');
57732 //var id = this.child('span').dom.textContent;
57735 Pman.Dialog.CourseCalendar.show({
57739 productitem_active : id ? 1 : 0
57741 _this.grid.ds.load({});
57746 _this.panel.fireEvent('resize', [ '', '' ]);
57749 loadResponse : function(o, success, response){
57750 // this is overridden on before load..
57752 Roo.log("our code?");
57753 //Roo.log(success);
57754 //Roo.log(response)
57755 delete this.activeRequest;
57757 this.fireEvent("loadexception", this, o, response);
57758 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57763 result = o.reader.read(response);
57765 Roo.log("load exception?");
57766 this.fireEvent("loadexception", this, o, response, e);
57767 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57770 Roo.log("ready...");
57771 // loop through result.records;
57772 // and set this.tdate[date] = [] << array of records..
57774 Roo.each(result.records, function(r){
57776 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
57777 _this.tdata[r.data.when_dt.format('j')] = [];
57779 _this.tdata[r.data.when_dt.format('j')].push(r.data);
57782 //Roo.log(_this.tdata);
57784 result.records = [];
57785 result.totalRecords = 6;
57787 // let's generate some duumy records for the rows.
57788 //var st = _this.dateField.getValue();
57790 // work out monday..
57791 //st = st.add(Date.DAY, -1 * st.format('w'));
57793 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57795 var firstOfMonth = date.getFirstDayOfMonth();
57796 var days = date.getDaysInMonth();
57798 var firstAdded = false;
57799 for (var i = 0; i < result.totalRecords ; i++) {
57800 //var d= st.add(Date.DAY, i);
57803 for(var w = 0 ; w < 7 ; w++){
57804 if(!firstAdded && firstOfMonth != w){
57811 var dd = (d > 0 && d < 10) ? "0"+d : d;
57812 row['weekday'+w] = String.format(
57813 '<span style="font-size: 16px;"><b>{0}</b></span>'+
57814 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
57816 date.format('Y-m-')+dd
57819 if(typeof(_this.tdata[d]) != 'undefined'){
57820 Roo.each(_this.tdata[d], function(r){
57824 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
57825 if(r.parent_id*1>0){
57826 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
57829 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
57830 deactive = 'de-act-link';
57833 row['weekday'+w] += String.format(
57834 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
57836 r.product_id_name, //1
57837 r.when_dt.format('h:ia'), //2
57847 // only do this if something added..
57849 result.records.push(_this.grid.dataSource.reader.newRow(row));
57853 // push it twice. (second one with an hour..
57857 this.fireEvent("load", this, o, o.request.arg);
57858 o.request.callback.call(o.request.scope, result, o.request.arg, true);
57860 sortInfo : {field: 'when_dt', direction : 'ASC' },
57862 xtype: 'HttpProxy',
57865 url : baseURL + '/Roo/Shop_course.php'
57868 xtype: 'JsonReader',
57885 'name': 'parent_id',
57889 'name': 'product_id',
57893 'name': 'productitem_id',
57911 click : function (_self, e)
57913 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57914 sd.setMonth(sd.getMonth()-1);
57915 _this.monthField.setValue(sd.format('Y-m-d'));
57916 _this.grid.ds.load({});
57922 xtype: 'Separator',
57926 xtype: 'MonthField',
57929 render : function (_self)
57931 _this.monthField = _self;
57932 // _this.monthField.set today
57934 select : function (combo, date)
57936 _this.grid.ds.load({});
57939 value : (function() { return new Date(); })()
57942 xtype: 'Separator',
57948 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
57958 click : function (_self, e)
57960 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57961 sd.setMonth(sd.getMonth()+1);
57962 _this.monthField.setValue(sd.format('Y-m-d'));
57963 _this.grid.ds.load({});
57976 * Ext JS Library 1.1.1
57977 * Copyright(c) 2006-2007, Ext JS, LLC.
57979 * Originally Released Under LGPL - original licence link has changed is not relivant.
57982 * <script type="text/javascript">
57986 * @class Roo.LoadMask
57987 * A simple utility class for generically masking elements while loading data. If the element being masked has
57988 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
57989 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
57990 * element's UpdateManager load indicator and will be destroyed after the initial load.
57992 * Create a new LoadMask
57993 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
57994 * @param {Object} config The config object
57996 Roo.LoadMask = function(el, config){
57997 this.el = Roo.get(el);
57998 Roo.apply(this, config);
58000 this.store.on('beforeload', this.onBeforeLoad, this);
58001 this.store.on('load', this.onLoad, this);
58002 this.store.on('loadexception', this.onLoadException, this);
58003 this.removeMask = false;
58005 var um = this.el.getUpdateManager();
58006 um.showLoadIndicator = false; // disable the default indicator
58007 um.on('beforeupdate', this.onBeforeLoad, this);
58008 um.on('update', this.onLoad, this);
58009 um.on('failure', this.onLoad, this);
58010 this.removeMask = true;
58014 Roo.LoadMask.prototype = {
58016 * @cfg {Boolean} removeMask
58017 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
58018 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
58021 * @cfg {String} msg
58022 * The text to display in a centered loading message box (defaults to 'Loading...')
58024 msg : 'Loading...',
58026 * @cfg {String} msgCls
58027 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
58029 msgCls : 'x-mask-loading',
58032 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
58038 * Disables the mask to prevent it from being displayed
58040 disable : function(){
58041 this.disabled = true;
58045 * Enables the mask so that it can be displayed
58047 enable : function(){
58048 this.disabled = false;
58051 onLoadException : function()
58053 Roo.log(arguments);
58055 if (typeof(arguments[3]) != 'undefined') {
58056 Roo.MessageBox.alert("Error loading",arguments[3]);
58060 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
58061 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
58070 this.el.unmask(this.removeMask);
58073 onLoad : function()
58075 this.el.unmask(this.removeMask);
58079 onBeforeLoad : function(){
58080 if(!this.disabled){
58081 this.el.mask(this.msg, this.msgCls);
58086 destroy : function(){
58088 this.store.un('beforeload', this.onBeforeLoad, this);
58089 this.store.un('load', this.onLoad, this);
58090 this.store.un('loadexception', this.onLoadException, this);
58092 var um = this.el.getUpdateManager();
58093 um.un('beforeupdate', this.onBeforeLoad, this);
58094 um.un('update', this.onLoad, this);
58095 um.un('failure', this.onLoad, this);
58100 * Ext JS Library 1.1.1
58101 * Copyright(c) 2006-2007, Ext JS, LLC.
58103 * Originally Released Under LGPL - original licence link has changed is not relivant.
58106 * <script type="text/javascript">
58111 * @class Roo.XTemplate
58112 * @extends Roo.Template
58113 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
58115 var t = new Roo.XTemplate(
58116 '<select name="{name}">',
58117 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
58121 // then append, applying the master template values
58124 * Supported features:
58129 {a_variable} - output encoded.
58130 {a_variable.format:("Y-m-d")} - call a method on the variable
58131 {a_variable:raw} - unencoded output
58132 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
58133 {a_variable:this.method_on_template(...)} - call a method on the template object.
58138 <tpl for="a_variable or condition.."></tpl>
58139 <tpl if="a_variable or condition"></tpl>
58140 <tpl exec="some javascript"></tpl>
58141 <tpl name="named_template"></tpl> (experimental)
58143 <tpl for="."></tpl> - just iterate the property..
58144 <tpl for=".."></tpl> - iterates with the parent (probably the template)
58148 Roo.XTemplate = function()
58150 Roo.XTemplate.superclass.constructor.apply(this, arguments);
58157 Roo.extend(Roo.XTemplate, Roo.Template, {
58160 * The various sub templates
58165 * basic tag replacing syntax
58168 * // you can fake an object call by doing this
58172 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58175 * compile the template
58177 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58180 compile: function()
58184 s = ['<tpl>', s, '</tpl>'].join('');
58186 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58187 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58188 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58189 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58190 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58195 while(true == !!(m = s.match(re))){
58196 var forMatch = m[0].match(nameRe),
58197 ifMatch = m[0].match(ifRe),
58198 execMatch = m[0].match(execRe),
58199 namedMatch = m[0].match(namedRe),
58204 name = forMatch && forMatch[1] ? forMatch[1] : '';
58207 // if - puts fn into test..
58208 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58210 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58215 // exec - calls a function... returns empty if true is returned.
58216 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58218 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58226 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58227 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58228 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58231 var uid = namedMatch ? namedMatch[1] : id;
58235 id: namedMatch ? namedMatch[1] : id,
58242 s = s.replace(m[0], '');
58244 s = s.replace(m[0], '{xtpl'+ id + '}');
58249 for(var i = tpls.length-1; i >= 0; --i){
58250 this.compileTpl(tpls[i]);
58251 this.tpls[tpls[i].id] = tpls[i];
58253 this.master = tpls[tpls.length-1];
58257 * same as applyTemplate, except it's done to one of the subTemplates
58258 * when using named templates, you can do:
58260 * var str = pl.applySubTemplate('your-name', values);
58263 * @param {Number} id of the template
58264 * @param {Object} values to apply to template
58265 * @param {Object} parent (normaly the instance of this object)
58267 applySubTemplate : function(id, values, parent)
58271 var t = this.tpls[id];
58275 if(t.test && !t.test.call(this, values, parent)){
58279 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58280 Roo.log(e.toString());
58286 if(t.exec && t.exec.call(this, values, parent)){
58290 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58291 Roo.log(e.toString());
58296 var vs = t.target ? t.target.call(this, values, parent) : values;
58297 parent = t.target ? values : parent;
58298 if(t.target && vs instanceof Array){
58300 for(var i = 0, len = vs.length; i < len; i++){
58301 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58303 return buf.join('');
58305 return t.compiled.call(this, vs, parent);
58307 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58308 Roo.log(e.toString());
58309 Roo.log(t.compiled);
58314 compileTpl : function(tpl)
58316 var fm = Roo.util.Format;
58317 var useF = this.disableFormats !== true;
58318 var sep = Roo.isGecko ? "+" : ",";
58319 var undef = function(str) {
58320 Roo.log("Property not found :" + str);
58324 var fn = function(m, name, format, args)
58326 //Roo.log(arguments);
58327 args = args ? args.replace(/\\'/g,"'") : args;
58328 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58329 if (typeof(format) == 'undefined') {
58330 format= 'htmlEncode';
58332 if (format == 'raw' ) {
58336 if(name.substr(0, 4) == 'xtpl'){
58337 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58340 // build an array of options to determine if value is undefined..
58342 // basically get 'xxxx.yyyy' then do
58343 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58344 // (function () { Roo.log("Property not found"); return ''; })() :
58349 Roo.each(name.split('.'), function(st) {
58350 lookfor += (lookfor.length ? '.': '') + st;
58351 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58354 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58357 if(format && useF){
58359 args = args ? ',' + args : "";
58361 if(format.substr(0, 5) != "this."){
58362 format = "fm." + format + '(';
58364 format = 'this.call("'+ format.substr(5) + '", ';
58368 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58372 // called with xxyx.yuu:(test,test)
58374 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58376 // raw.. - :raw modifier..
58377 return "'"+ sep + udef_st + name + ")"+sep+"'";
58381 // branched to use + in gecko and [].join() in others
58383 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58384 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58387 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58388 body.push(tpl.body.replace(/(\r\n|\n)/g,
58389 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58390 body.push("'].join('');};};");
58391 body = body.join('');
58394 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58396 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58402 applyTemplate : function(values){
58403 return this.master.compiled.call(this, values, {});
58404 //var s = this.subs;
58407 apply : function(){
58408 return this.applyTemplate.apply(this, arguments);
58413 Roo.XTemplate.from = function(el){
58414 el = Roo.getDom(el);
58415 return new Roo.XTemplate(el.value || el.innerHTML);