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"){
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 if (typeof(depreciated_tpl) == 'undefined') {
24857 // new way.. - universal constructor.
24858 Roo.apply(this, config);
24859 this.el = Roo.get(this.el);
24862 this.el = Roo.get(config);
24863 this.tpl = depreciated_tpl;
24864 Roo.apply(this, depreciated_config);
24866 this.wrapEl = this.el.wrap().wrap();
24867 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24870 if(typeof(this.tpl) == "string"){
24871 this.tpl = new Roo.Template(this.tpl);
24873 // support xtype ctors..
24874 this.tpl = new Roo.factory(this.tpl, Roo);
24878 this.tpl.compile();
24886 * @event beforeclick
24887 * Fires before a click is processed. Returns false to cancel the default action.
24888 * @param {Roo.View} this
24889 * @param {Number} index The index of the target node
24890 * @param {HTMLElement} node The target node
24891 * @param {Roo.EventObject} e The raw event object
24893 "beforeclick" : true,
24896 * Fires when a template node is clicked.
24897 * @param {Roo.View} this
24898 * @param {Number} index The index of the target node
24899 * @param {HTMLElement} node The target node
24900 * @param {Roo.EventObject} e The raw event object
24905 * Fires when a template node is double clicked.
24906 * @param {Roo.View} this
24907 * @param {Number} index The index of the target node
24908 * @param {HTMLElement} node The target node
24909 * @param {Roo.EventObject} e The raw event object
24913 * @event contextmenu
24914 * Fires when a template node is right clicked.
24915 * @param {Roo.View} this
24916 * @param {Number} index The index of the target node
24917 * @param {HTMLElement} node The target node
24918 * @param {Roo.EventObject} e The raw event object
24920 "contextmenu" : true,
24922 * @event selectionchange
24923 * Fires when the selected nodes change.
24924 * @param {Roo.View} this
24925 * @param {Array} selections Array of the selected nodes
24927 "selectionchange" : true,
24930 * @event beforeselect
24931 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24932 * @param {Roo.View} this
24933 * @param {HTMLElement} node The node to be selected
24934 * @param {Array} selections Array of currently selected nodes
24936 "beforeselect" : true,
24938 * @event preparedata
24939 * Fires on every row to render, to allow you to change the data.
24940 * @param {Roo.View} this
24941 * @param {Object} data to be rendered (change this)
24943 "preparedata" : true
24951 "click": this.onClick,
24952 "dblclick": this.onDblClick,
24953 "contextmenu": this.onContextMenu,
24957 this.selections = [];
24959 this.cmp = new Roo.CompositeElementLite([]);
24961 this.store = Roo.factory(this.store, Roo.data);
24962 this.setStore(this.store, true);
24965 if ( this.footer && this.footer.xtype) {
24967 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24969 this.footer.dataSource = this.store
24970 this.footer.container = fctr;
24971 this.footer = Roo.factory(this.footer, Roo);
24972 fctr.insertFirst(this.el);
24974 // this is a bit insane - as the paging toolbar seems to detach the el..
24975 // dom.parentNode.parentNode.parentNode
24976 // they get detached?
24980 Roo.View.superclass.constructor.call(this);
24985 Roo.extend(Roo.View, Roo.util.Observable, {
24988 * @cfg {Roo.data.Store} store Data store to load data from.
24993 * @cfg {String|Roo.Element} el The container element.
24998 * @cfg {String|Roo.Template} tpl The template used by this View
25002 * @cfg {String} dataName the named area of the template to use as the data area
25003 * Works with domtemplates roo-name="name"
25007 * @cfg {String} selectedClass The css class to add to selected nodes
25009 selectedClass : "x-view-selected",
25011 * @cfg {String} emptyText The empty text to show when nothing is loaded.
25016 * @cfg {String} text to display on mask (default Loading)
25020 * @cfg {Boolean} multiSelect Allow multiple selection
25022 multiSelect : false,
25024 * @cfg {Boolean} singleSelect Allow single selection
25026 singleSelect: false,
25029 * @cfg {Boolean} toggleSelect - selecting
25031 toggleSelect : false,
25034 * Returns the element this view is bound to.
25035 * @return {Roo.Element}
25037 getEl : function(){
25038 return this.wrapEl;
25044 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25046 refresh : function(){
25047 Roo.log('refresh');
25050 // if we are using something like 'domtemplate', then
25051 // the what gets used is:
25052 // t.applySubtemplate(NAME, data, wrapping data..)
25053 // the outer template then get' applied with
25054 // the store 'extra data'
25055 // and the body get's added to the
25056 // roo-name="data" node?
25057 // <span class='roo-tpl-{name}'></span> ?????
25061 this.clearSelections();
25062 this.el.update("");
25064 var records = this.store.getRange();
25065 if(records.length < 1) {
25067 // is this valid?? = should it render a template??
25069 this.el.update(this.emptyText);
25073 if (this.dataName) {
25074 this.el.update(t.apply(this.store.meta)); //????
25075 el = this.el.child('.roo-tpl-' + this.dataName);
25078 for(var i = 0, len = records.length; i < len; i++){
25079 var data = this.prepareData(records[i].data, i, records[i]);
25080 this.fireEvent("preparedata", this, data, i, records[i]);
25081 html[html.length] = Roo.util.Format.trim(
25083 t.applySubtemplate(this.dataName, data, this.store.meta) :
25090 el.update(html.join(""));
25091 this.nodes = el.dom.childNodes;
25092 this.updateIndexes(0);
25097 * Function to override to reformat the data that is sent to
25098 * the template for each node.
25099 * DEPRICATED - use the preparedata event handler.
25100 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25101 * a JSON object for an UpdateManager bound view).
25103 prepareData : function(data, index, record)
25105 this.fireEvent("preparedata", this, data, index, record);
25109 onUpdate : function(ds, record){
25110 Roo.log('on update');
25111 this.clearSelections();
25112 var index = this.store.indexOf(record);
25113 var n = this.nodes[index];
25114 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25115 n.parentNode.removeChild(n);
25116 this.updateIndexes(index, index);
25122 onAdd : function(ds, records, index)
25124 Roo.log(['on Add', ds, records, index] );
25125 this.clearSelections();
25126 if(this.nodes.length == 0){
25130 var n = this.nodes[index];
25131 for(var i = 0, len = records.length; i < len; i++){
25132 var d = this.prepareData(records[i].data, i, records[i]);
25134 this.tpl.insertBefore(n, d);
25137 this.tpl.append(this.el, d);
25140 this.updateIndexes(index);
25143 onRemove : function(ds, record, index){
25144 Roo.log('onRemove');
25145 this.clearSelections();
25146 var el = this.dataName ?
25147 this.el.child('.roo-tpl-' + this.dataName) :
25150 el.dom.removeChild(this.nodes[index]);
25151 this.updateIndexes(index);
25155 * Refresh an individual node.
25156 * @param {Number} index
25158 refreshNode : function(index){
25159 this.onUpdate(this.store, this.store.getAt(index));
25162 updateIndexes : function(startIndex, endIndex){
25163 var ns = this.nodes;
25164 startIndex = startIndex || 0;
25165 endIndex = endIndex || ns.length - 1;
25166 for(var i = startIndex; i <= endIndex; i++){
25167 ns[i].nodeIndex = i;
25172 * Changes the data store this view uses and refresh the view.
25173 * @param {Store} store
25175 setStore : function(store, initial){
25176 if(!initial && this.store){
25177 this.store.un("datachanged", this.refresh);
25178 this.store.un("add", this.onAdd);
25179 this.store.un("remove", this.onRemove);
25180 this.store.un("update", this.onUpdate);
25181 this.store.un("clear", this.refresh);
25182 this.store.un("beforeload", this.onBeforeLoad);
25183 this.store.un("load", this.onLoad);
25184 this.store.un("loadexception", this.onLoad);
25188 store.on("datachanged", this.refresh, this);
25189 store.on("add", this.onAdd, this);
25190 store.on("remove", this.onRemove, this);
25191 store.on("update", this.onUpdate, this);
25192 store.on("clear", this.refresh, this);
25193 store.on("beforeload", this.onBeforeLoad, this);
25194 store.on("load", this.onLoad, this);
25195 store.on("loadexception", this.onLoad, this);
25203 * onbeforeLoad - masks the loading area.
25206 onBeforeLoad : function(store,opts)
25208 Roo.log('onBeforeLoad');
25210 this.el.update("");
25212 this.el.mask(this.mask ? this.mask : "Loading" );
25214 onLoad : function ()
25221 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25222 * @param {HTMLElement} node
25223 * @return {HTMLElement} The template node
25225 findItemFromChild : function(node){
25226 var el = this.dataName ?
25227 this.el.child('.roo-tpl-' + this.dataName,true) :
25230 if(!node || node.parentNode == el){
25233 var p = node.parentNode;
25234 while(p && p != el){
25235 if(p.parentNode == el){
25244 onClick : function(e){
25245 var item = this.findItemFromChild(e.getTarget());
25247 var index = this.indexOf(item);
25248 if(this.onItemClick(item, index, e) !== false){
25249 this.fireEvent("click", this, index, item, e);
25252 this.clearSelections();
25257 onContextMenu : function(e){
25258 var item = this.findItemFromChild(e.getTarget());
25260 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25265 onDblClick : function(e){
25266 var item = this.findItemFromChild(e.getTarget());
25268 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25272 onItemClick : function(item, index, e)
25274 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25277 if (this.toggleSelect) {
25278 var m = this.isSelected(item) ? 'unselect' : 'select';
25281 _t[m](item, true, false);
25284 if(this.multiSelect || this.singleSelect){
25285 if(this.multiSelect && e.shiftKey && this.lastSelection){
25286 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25288 this.select(item, this.multiSelect && e.ctrlKey);
25289 this.lastSelection = item;
25291 e.preventDefault();
25297 * Get the number of selected nodes.
25300 getSelectionCount : function(){
25301 return this.selections.length;
25305 * Get the currently selected nodes.
25306 * @return {Array} An array of HTMLElements
25308 getSelectedNodes : function(){
25309 return this.selections;
25313 * Get the indexes of the selected nodes.
25316 getSelectedIndexes : function(){
25317 var indexes = [], s = this.selections;
25318 for(var i = 0, len = s.length; i < len; i++){
25319 indexes.push(s[i].nodeIndex);
25325 * Clear all selections
25326 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25328 clearSelections : function(suppressEvent){
25329 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25330 this.cmp.elements = this.selections;
25331 this.cmp.removeClass(this.selectedClass);
25332 this.selections = [];
25333 if(!suppressEvent){
25334 this.fireEvent("selectionchange", this, this.selections);
25340 * Returns true if the passed node is selected
25341 * @param {HTMLElement/Number} node The node or node index
25342 * @return {Boolean}
25344 isSelected : function(node){
25345 var s = this.selections;
25349 node = this.getNode(node);
25350 return s.indexOf(node) !== -1;
25355 * @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
25356 * @param {Boolean} keepExisting (optional) true to keep existing selections
25357 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25359 select : function(nodeInfo, keepExisting, suppressEvent){
25360 if(nodeInfo instanceof Array){
25362 this.clearSelections(true);
25364 for(var i = 0, len = nodeInfo.length; i < len; i++){
25365 this.select(nodeInfo[i], true, true);
25369 var node = this.getNode(nodeInfo);
25370 if(!node || this.isSelected(node)){
25371 return; // already selected.
25374 this.clearSelections(true);
25376 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25377 Roo.fly(node).addClass(this.selectedClass);
25378 this.selections.push(node);
25379 if(!suppressEvent){
25380 this.fireEvent("selectionchange", this, this.selections);
25388 * @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
25389 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25390 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25392 unselect : function(nodeInfo, keepExisting, suppressEvent)
25394 if(nodeInfo instanceof Array){
25395 Roo.each(this.selections, function(s) {
25396 this.unselect(s, nodeInfo);
25400 var node = this.getNode(nodeInfo);
25401 if(!node || !this.isSelected(node)){
25402 Roo.log("not selected");
25403 return; // not selected.
25407 Roo.each(this.selections, function(s) {
25409 Roo.fly(node).removeClass(this.selectedClass);
25416 this.selections= ns;
25417 this.fireEvent("selectionchange", this, this.selections);
25421 * Gets a template node.
25422 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25423 * @return {HTMLElement} The node or null if it wasn't found
25425 getNode : function(nodeInfo){
25426 if(typeof nodeInfo == "string"){
25427 return document.getElementById(nodeInfo);
25428 }else if(typeof nodeInfo == "number"){
25429 return this.nodes[nodeInfo];
25435 * Gets a range template nodes.
25436 * @param {Number} startIndex
25437 * @param {Number} endIndex
25438 * @return {Array} An array of nodes
25440 getNodes : function(start, end){
25441 var ns = this.nodes;
25442 start = start || 0;
25443 end = typeof end == "undefined" ? ns.length - 1 : end;
25446 for(var i = start; i <= end; i++){
25450 for(var i = start; i >= end; i--){
25458 * Finds the index of the passed node
25459 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25460 * @return {Number} The index of the node or -1
25462 indexOf : function(node){
25463 node = this.getNode(node);
25464 if(typeof node.nodeIndex == "number"){
25465 return node.nodeIndex;
25467 var ns = this.nodes;
25468 for(var i = 0, len = ns.length; i < len; i++){
25478 * Ext JS Library 1.1.1
25479 * Copyright(c) 2006-2007, Ext JS, LLC.
25481 * Originally Released Under LGPL - original licence link has changed is not relivant.
25484 * <script type="text/javascript">
25488 * @class Roo.JsonView
25489 * @extends Roo.View
25490 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25492 var view = new Roo.JsonView({
25493 container: "my-element",
25494 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25499 // listen for node click?
25500 view.on("click", function(vw, index, node, e){
25501 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25504 // direct load of JSON data
25505 view.load("foobar.php");
25507 // Example from my blog list
25508 var tpl = new Roo.Template(
25509 '<div class="entry">' +
25510 '<a class="entry-title" href="{link}">{title}</a>' +
25511 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25512 "</div><hr />"
25515 var moreView = new Roo.JsonView({
25516 container : "entry-list",
25520 moreView.on("beforerender", this.sortEntries, this);
25522 url: "/blog/get-posts.php",
25523 params: "allposts=true",
25524 text: "Loading Blog Entries..."
25528 * Note: old code is supported with arguments : (container, template, config)
25532 * Create a new JsonView
25534 * @param {Object} config The config object
25537 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25540 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25542 var um = this.el.getUpdateManager();
25543 um.setRenderer(this);
25544 um.on("update", this.onLoad, this);
25545 um.on("failure", this.onLoadException, this);
25548 * @event beforerender
25549 * Fires before rendering of the downloaded JSON data.
25550 * @param {Roo.JsonView} this
25551 * @param {Object} data The JSON data loaded
25555 * Fires when data is loaded.
25556 * @param {Roo.JsonView} this
25557 * @param {Object} data The JSON data loaded
25558 * @param {Object} response The raw Connect response object
25561 * @event loadexception
25562 * Fires when loading fails.
25563 * @param {Roo.JsonView} this
25564 * @param {Object} response The raw Connect response object
25567 'beforerender' : true,
25569 'loadexception' : true
25572 Roo.extend(Roo.JsonView, Roo.View, {
25574 * @type {String} The root property in the loaded JSON object that contains the data
25579 * Refreshes the view.
25581 refresh : function(){
25582 this.clearSelections();
25583 this.el.update("");
25585 var o = this.jsonData;
25586 if(o && o.length > 0){
25587 for(var i = 0, len = o.length; i < len; i++){
25588 var data = this.prepareData(o[i], i, o);
25589 html[html.length] = this.tpl.apply(data);
25592 html.push(this.emptyText);
25594 this.el.update(html.join(""));
25595 this.nodes = this.el.dom.childNodes;
25596 this.updateIndexes(0);
25600 * 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.
25601 * @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:
25604 url: "your-url.php",
25605 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25606 callback: yourFunction,
25607 scope: yourObject, //(optional scope)
25610 text: "Loading...",
25615 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25616 * 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.
25617 * @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}
25618 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25619 * @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.
25622 var um = this.el.getUpdateManager();
25623 um.update.apply(um, arguments);
25626 render : function(el, response){
25627 this.clearSelections();
25628 this.el.update("");
25631 o = Roo.util.JSON.decode(response.responseText);
25634 o = o[this.jsonRoot];
25639 * The current JSON data or null
25642 this.beforeRender();
25647 * Get the number of records in the current JSON dataset
25650 getCount : function(){
25651 return this.jsonData ? this.jsonData.length : 0;
25655 * Returns the JSON object for the specified node(s)
25656 * @param {HTMLElement/Array} node The node or an array of nodes
25657 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25658 * you get the JSON object for the node
25660 getNodeData : function(node){
25661 if(node instanceof Array){
25663 for(var i = 0, len = node.length; i < len; i++){
25664 data.push(this.getNodeData(node[i]));
25668 return this.jsonData[this.indexOf(node)] || null;
25671 beforeRender : function(){
25672 this.snapshot = this.jsonData;
25674 this.sort.apply(this, this.sortInfo);
25676 this.fireEvent("beforerender", this, this.jsonData);
25679 onLoad : function(el, o){
25680 this.fireEvent("load", this, this.jsonData, o);
25683 onLoadException : function(el, o){
25684 this.fireEvent("loadexception", this, o);
25688 * Filter the data by a specific property.
25689 * @param {String} property A property on your JSON objects
25690 * @param {String/RegExp} value Either string that the property values
25691 * should start with, or a RegExp to test against the property
25693 filter : function(property, value){
25696 var ss = this.snapshot;
25697 if(typeof value == "string"){
25698 var vlen = value.length;
25700 this.clearFilter();
25703 value = value.toLowerCase();
25704 for(var i = 0, len = ss.length; i < len; i++){
25706 if(o[property].substr(0, vlen).toLowerCase() == value){
25710 } else if(value.exec){ // regex?
25711 for(var i = 0, len = ss.length; i < len; i++){
25713 if(value.test(o[property])){
25720 this.jsonData = data;
25726 * Filter by a function. The passed function will be called with each
25727 * object in the current dataset. If the function returns true the value is kept,
25728 * otherwise it is filtered.
25729 * @param {Function} fn
25730 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25732 filterBy : function(fn, scope){
25735 var ss = this.snapshot;
25736 for(var i = 0, len = ss.length; i < len; i++){
25738 if(fn.call(scope || this, o)){
25742 this.jsonData = data;
25748 * Clears the current filter.
25750 clearFilter : function(){
25751 if(this.snapshot && this.jsonData != this.snapshot){
25752 this.jsonData = this.snapshot;
25759 * Sorts the data for this view and refreshes it.
25760 * @param {String} property A property on your JSON objects to sort on
25761 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25762 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25764 sort : function(property, dir, sortType){
25765 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25768 var dsc = dir && dir.toLowerCase() == "desc";
25769 var f = function(o1, o2){
25770 var v1 = sortType ? sortType(o1[p]) : o1[p];
25771 var v2 = sortType ? sortType(o2[p]) : o2[p];
25774 return dsc ? +1 : -1;
25775 } else if(v1 > v2){
25776 return dsc ? -1 : +1;
25781 this.jsonData.sort(f);
25783 if(this.jsonData != this.snapshot){
25784 this.snapshot.sort(f);
25790 * Ext JS Library 1.1.1
25791 * Copyright(c) 2006-2007, Ext JS, LLC.
25793 * Originally Released Under LGPL - original licence link has changed is not relivant.
25796 * <script type="text/javascript">
25801 * @class Roo.ColorPalette
25802 * @extends Roo.Component
25803 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25804 * Here's an example of typical usage:
25806 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25807 cp.render('my-div');
25809 cp.on('select', function(palette, selColor){
25810 // do something with selColor
25814 * Create a new ColorPalette
25815 * @param {Object} config The config object
25817 Roo.ColorPalette = function(config){
25818 Roo.ColorPalette.superclass.constructor.call(this, config);
25822 * Fires when a color is selected
25823 * @param {ColorPalette} this
25824 * @param {String} color The 6-digit color hex code (without the # symbol)
25830 this.on("select", this.handler, this.scope, true);
25833 Roo.extend(Roo.ColorPalette, Roo.Component, {
25835 * @cfg {String} itemCls
25836 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25838 itemCls : "x-color-palette",
25840 * @cfg {String} value
25841 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25842 * the hex codes are case-sensitive.
25845 clickEvent:'click',
25847 ctype: "Roo.ColorPalette",
25850 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25852 allowReselect : false,
25855 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25856 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25857 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25858 * of colors with the width setting until the box is symmetrical.</p>
25859 * <p>You can override individual colors if needed:</p>
25861 var cp = new Roo.ColorPalette();
25862 cp.colors[0] = "FF0000"; // change the first box to red
25865 Or you can provide a custom array of your own for complete control:
25867 var cp = new Roo.ColorPalette();
25868 cp.colors = ["000000", "993300", "333300"];
25873 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25874 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25875 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25876 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25877 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25881 onRender : function(container, position){
25882 var t = new Roo.MasterTemplate(
25883 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25885 var c = this.colors;
25886 for(var i = 0, len = c.length; i < len; i++){
25889 var el = document.createElement("div");
25890 el.className = this.itemCls;
25892 container.dom.insertBefore(el, position);
25893 this.el = Roo.get(el);
25894 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25895 if(this.clickEvent != 'click'){
25896 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25901 afterRender : function(){
25902 Roo.ColorPalette.superclass.afterRender.call(this);
25904 var s = this.value;
25911 handleClick : function(e, t){
25912 e.preventDefault();
25913 if(!this.disabled){
25914 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25915 this.select(c.toUpperCase());
25920 * Selects the specified color in the palette (fires the select event)
25921 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25923 select : function(color){
25924 color = color.replace("#", "");
25925 if(color != this.value || this.allowReselect){
25928 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25930 el.child("a.color-"+color).addClass("x-color-palette-sel");
25931 this.value = color;
25932 this.fireEvent("select", this, color);
25937 * Ext JS Library 1.1.1
25938 * Copyright(c) 2006-2007, Ext JS, LLC.
25940 * Originally Released Under LGPL - original licence link has changed is not relivant.
25943 * <script type="text/javascript">
25947 * @class Roo.DatePicker
25948 * @extends Roo.Component
25949 * Simple date picker class.
25951 * Create a new DatePicker
25952 * @param {Object} config The config object
25954 Roo.DatePicker = function(config){
25955 Roo.DatePicker.superclass.constructor.call(this, config);
25957 this.value = config && config.value ?
25958 config.value.clearTime() : new Date().clearTime();
25963 * Fires when a date is selected
25964 * @param {DatePicker} this
25965 * @param {Date} date The selected date
25969 * @event monthchange
25970 * Fires when the displayed month changes
25971 * @param {DatePicker} this
25972 * @param {Date} date The selected month
25974 'monthchange': true
25978 this.on("select", this.handler, this.scope || this);
25980 // build the disabledDatesRE
25981 if(!this.disabledDatesRE && this.disabledDates){
25982 var dd = this.disabledDates;
25984 for(var i = 0; i < dd.length; i++){
25986 if(i != dd.length-1) re += "|";
25988 this.disabledDatesRE = new RegExp(re + ")");
25992 Roo.extend(Roo.DatePicker, Roo.Component, {
25994 * @cfg {String} todayText
25995 * The text to display on the button that selects the current date (defaults to "Today")
25997 todayText : "Today",
25999 * @cfg {String} okText
26000 * The text to display on the ok button
26002 okText : " OK ", //   to give the user extra clicking room
26004 * @cfg {String} cancelText
26005 * The text to display on the cancel button
26007 cancelText : "Cancel",
26009 * @cfg {String} todayTip
26010 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
26012 todayTip : "{0} (Spacebar)",
26014 * @cfg {Date} minDate
26015 * Minimum allowable date (JavaScript date object, defaults to null)
26019 * @cfg {Date} maxDate
26020 * Maximum allowable date (JavaScript date object, defaults to null)
26024 * @cfg {String} minText
26025 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
26027 minText : "This date is before the minimum date",
26029 * @cfg {String} maxText
26030 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
26032 maxText : "This date is after the maximum date",
26034 * @cfg {String} format
26035 * The default date format string which can be overriden for localization support. The format must be
26036 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26040 * @cfg {Array} disabledDays
26041 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26043 disabledDays : null,
26045 * @cfg {String} disabledDaysText
26046 * The tooltip to display when the date falls on a disabled day (defaults to "")
26048 disabledDaysText : "",
26050 * @cfg {RegExp} disabledDatesRE
26051 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26053 disabledDatesRE : null,
26055 * @cfg {String} disabledDatesText
26056 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26058 disabledDatesText : "",
26060 * @cfg {Boolean} constrainToViewport
26061 * True to constrain the date picker to the viewport (defaults to true)
26063 constrainToViewport : true,
26065 * @cfg {Array} monthNames
26066 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26068 monthNames : Date.monthNames,
26070 * @cfg {Array} dayNames
26071 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26073 dayNames : Date.dayNames,
26075 * @cfg {String} nextText
26076 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26078 nextText: 'Next Month (Control+Right)',
26080 * @cfg {String} prevText
26081 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26083 prevText: 'Previous Month (Control+Left)',
26085 * @cfg {String} monthYearText
26086 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26088 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26090 * @cfg {Number} startDay
26091 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26095 * @cfg {Bool} showClear
26096 * Show a clear button (usefull for date form elements that can be blank.)
26102 * Sets the value of the date field
26103 * @param {Date} value The date to set
26105 setValue : function(value){
26106 var old = this.value;
26108 if (typeof(value) == 'string') {
26110 value = Date.parseDate(value, this.format);
26113 value = new Date();
26116 this.value = value.clearTime(true);
26118 this.update(this.value);
26123 * Gets the current selected value of the date field
26124 * @return {Date} The selected date
26126 getValue : function(){
26131 focus : function(){
26133 this.update(this.activeDate);
26138 onRender : function(container, position){
26141 '<table cellspacing="0">',
26142 '<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>',
26143 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26144 var dn = this.dayNames;
26145 for(var i = 0; i < 7; i++){
26146 var d = this.startDay+i;
26150 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26152 m[m.length] = "</tr></thead><tbody><tr>";
26153 for(var i = 0; i < 42; i++) {
26154 if(i % 7 == 0 && i != 0){
26155 m[m.length] = "</tr><tr>";
26157 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26159 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26160 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26162 var el = document.createElement("div");
26163 el.className = "x-date-picker";
26164 el.innerHTML = m.join("");
26166 container.dom.insertBefore(el, position);
26168 this.el = Roo.get(el);
26169 this.eventEl = Roo.get(el.firstChild);
26171 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26172 handler: this.showPrevMonth,
26174 preventDefault:true,
26178 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26179 handler: this.showNextMonth,
26181 preventDefault:true,
26185 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26187 this.monthPicker = this.el.down('div.x-date-mp');
26188 this.monthPicker.enableDisplayMode('block');
26190 var kn = new Roo.KeyNav(this.eventEl, {
26191 "left" : function(e){
26193 this.showPrevMonth() :
26194 this.update(this.activeDate.add("d", -1));
26197 "right" : function(e){
26199 this.showNextMonth() :
26200 this.update(this.activeDate.add("d", 1));
26203 "up" : function(e){
26205 this.showNextYear() :
26206 this.update(this.activeDate.add("d", -7));
26209 "down" : function(e){
26211 this.showPrevYear() :
26212 this.update(this.activeDate.add("d", 7));
26215 "pageUp" : function(e){
26216 this.showNextMonth();
26219 "pageDown" : function(e){
26220 this.showPrevMonth();
26223 "enter" : function(e){
26224 e.stopPropagation();
26231 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26233 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26235 this.el.unselectable();
26237 this.cells = this.el.select("table.x-date-inner tbody td");
26238 this.textNodes = this.el.query("table.x-date-inner tbody span");
26240 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26242 tooltip: this.monthYearText
26245 this.mbtn.on('click', this.showMonthPicker, this);
26246 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26249 var today = (new Date()).dateFormat(this.format);
26251 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26252 if (this.showClear) {
26253 baseTb.add( new Roo.Toolbar.Fill());
26256 text: String.format(this.todayText, today),
26257 tooltip: String.format(this.todayTip, today),
26258 handler: this.selectToday,
26262 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26265 if (this.showClear) {
26267 baseTb.add( new Roo.Toolbar.Fill());
26270 cls: 'x-btn-icon x-btn-clear',
26271 handler: function() {
26273 this.fireEvent("select", this, '');
26283 this.update(this.value);
26286 createMonthPicker : function(){
26287 if(!this.monthPicker.dom.firstChild){
26288 var buf = ['<table border="0" cellspacing="0">'];
26289 for(var i = 0; i < 6; i++){
26291 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26292 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26294 '<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>' :
26295 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26299 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26301 '</button><button type="button" class="x-date-mp-cancel">',
26303 '</button></td></tr>',
26306 this.monthPicker.update(buf.join(''));
26307 this.monthPicker.on('click', this.onMonthClick, this);
26308 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26310 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26311 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26313 this.mpMonths.each(function(m, a, i){
26316 m.dom.xmonth = 5 + Math.round(i * .5);
26318 m.dom.xmonth = Math.round((i-1) * .5);
26324 showMonthPicker : function(){
26325 this.createMonthPicker();
26326 var size = this.el.getSize();
26327 this.monthPicker.setSize(size);
26328 this.monthPicker.child('table').setSize(size);
26330 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26331 this.updateMPMonth(this.mpSelMonth);
26332 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26333 this.updateMPYear(this.mpSelYear);
26335 this.monthPicker.slideIn('t', {duration:.2});
26338 updateMPYear : function(y){
26340 var ys = this.mpYears.elements;
26341 for(var i = 1; i <= 10; i++){
26342 var td = ys[i-1], y2;
26344 y2 = y + Math.round(i * .5);
26345 td.firstChild.innerHTML = y2;
26348 y2 = y - (5-Math.round(i * .5));
26349 td.firstChild.innerHTML = y2;
26352 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26356 updateMPMonth : function(sm){
26357 this.mpMonths.each(function(m, a, i){
26358 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26362 selectMPMonth: function(m){
26366 onMonthClick : function(e, t){
26368 var el = new Roo.Element(t), pn;
26369 if(el.is('button.x-date-mp-cancel')){
26370 this.hideMonthPicker();
26372 else if(el.is('button.x-date-mp-ok')){
26373 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26374 this.hideMonthPicker();
26376 else if(pn = el.up('td.x-date-mp-month', 2)){
26377 this.mpMonths.removeClass('x-date-mp-sel');
26378 pn.addClass('x-date-mp-sel');
26379 this.mpSelMonth = pn.dom.xmonth;
26381 else if(pn = el.up('td.x-date-mp-year', 2)){
26382 this.mpYears.removeClass('x-date-mp-sel');
26383 pn.addClass('x-date-mp-sel');
26384 this.mpSelYear = pn.dom.xyear;
26386 else if(el.is('a.x-date-mp-prev')){
26387 this.updateMPYear(this.mpyear-10);
26389 else if(el.is('a.x-date-mp-next')){
26390 this.updateMPYear(this.mpyear+10);
26394 onMonthDblClick : function(e, t){
26396 var el = new Roo.Element(t), pn;
26397 if(pn = el.up('td.x-date-mp-month', 2)){
26398 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26399 this.hideMonthPicker();
26401 else if(pn = el.up('td.x-date-mp-year', 2)){
26402 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26403 this.hideMonthPicker();
26407 hideMonthPicker : function(disableAnim){
26408 if(this.monthPicker){
26409 if(disableAnim === true){
26410 this.monthPicker.hide();
26412 this.monthPicker.slideOut('t', {duration:.2});
26418 showPrevMonth : function(e){
26419 this.update(this.activeDate.add("mo", -1));
26423 showNextMonth : function(e){
26424 this.update(this.activeDate.add("mo", 1));
26428 showPrevYear : function(){
26429 this.update(this.activeDate.add("y", -1));
26433 showNextYear : function(){
26434 this.update(this.activeDate.add("y", 1));
26438 handleMouseWheel : function(e){
26439 var delta = e.getWheelDelta();
26441 this.showPrevMonth();
26443 } else if(delta < 0){
26444 this.showNextMonth();
26450 handleDateClick : function(e, t){
26452 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26453 this.setValue(new Date(t.dateValue));
26454 this.fireEvent("select", this, this.value);
26459 selectToday : function(){
26460 this.setValue(new Date().clearTime());
26461 this.fireEvent("select", this, this.value);
26465 update : function(date)
26467 var vd = this.activeDate;
26468 this.activeDate = date;
26470 var t = date.getTime();
26471 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26472 this.cells.removeClass("x-date-selected");
26473 this.cells.each(function(c){
26474 if(c.dom.firstChild.dateValue == t){
26475 c.addClass("x-date-selected");
26476 setTimeout(function(){
26477 try{c.dom.firstChild.focus();}catch(e){}
26486 var days = date.getDaysInMonth();
26487 var firstOfMonth = date.getFirstDateOfMonth();
26488 var startingPos = firstOfMonth.getDay()-this.startDay;
26490 if(startingPos <= this.startDay){
26494 var pm = date.add("mo", -1);
26495 var prevStart = pm.getDaysInMonth()-startingPos;
26497 var cells = this.cells.elements;
26498 var textEls = this.textNodes;
26499 days += startingPos;
26501 // convert everything to numbers so it's fast
26502 var day = 86400000;
26503 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26504 var today = new Date().clearTime().getTime();
26505 var sel = date.clearTime().getTime();
26506 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26507 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26508 var ddMatch = this.disabledDatesRE;
26509 var ddText = this.disabledDatesText;
26510 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26511 var ddaysText = this.disabledDaysText;
26512 var format = this.format;
26514 var setCellClass = function(cal, cell){
26516 var t = d.getTime();
26517 cell.firstChild.dateValue = t;
26519 cell.className += " x-date-today";
26520 cell.title = cal.todayText;
26523 cell.className += " x-date-selected";
26524 setTimeout(function(){
26525 try{cell.firstChild.focus();}catch(e){}
26530 cell.className = " x-date-disabled";
26531 cell.title = cal.minText;
26535 cell.className = " x-date-disabled";
26536 cell.title = cal.maxText;
26540 if(ddays.indexOf(d.getDay()) != -1){
26541 cell.title = ddaysText;
26542 cell.className = " x-date-disabled";
26545 if(ddMatch && format){
26546 var fvalue = d.dateFormat(format);
26547 if(ddMatch.test(fvalue)){
26548 cell.title = ddText.replace("%0", fvalue);
26549 cell.className = " x-date-disabled";
26555 for(; i < startingPos; i++) {
26556 textEls[i].innerHTML = (++prevStart);
26557 d.setDate(d.getDate()+1);
26558 cells[i].className = "x-date-prevday";
26559 setCellClass(this, cells[i]);
26561 for(; i < days; i++){
26562 intDay = i - startingPos + 1;
26563 textEls[i].innerHTML = (intDay);
26564 d.setDate(d.getDate()+1);
26565 cells[i].className = "x-date-active";
26566 setCellClass(this, cells[i]);
26569 for(; i < 42; i++) {
26570 textEls[i].innerHTML = (++extraDays);
26571 d.setDate(d.getDate()+1);
26572 cells[i].className = "x-date-nextday";
26573 setCellClass(this, cells[i]);
26576 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26577 this.fireEvent('monthchange', this, date);
26579 if(!this.internalRender){
26580 var main = this.el.dom.firstChild;
26581 var w = main.offsetWidth;
26582 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26583 Roo.fly(main).setWidth(w);
26584 this.internalRender = true;
26585 // opera does not respect the auto grow header center column
26586 // then, after it gets a width opera refuses to recalculate
26587 // without a second pass
26588 if(Roo.isOpera && !this.secondPass){
26589 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26590 this.secondPass = true;
26591 this.update.defer(10, this, [date]);
26599 * Ext JS Library 1.1.1
26600 * Copyright(c) 2006-2007, Ext JS, LLC.
26602 * Originally Released Under LGPL - original licence link has changed is not relivant.
26605 * <script type="text/javascript">
26608 * @class Roo.TabPanel
26609 * @extends Roo.util.Observable
26610 * A lightweight tab container.
26614 // basic tabs 1, built from existing content
26615 var tabs = new Roo.TabPanel("tabs1");
26616 tabs.addTab("script", "View Script");
26617 tabs.addTab("markup", "View Markup");
26618 tabs.activate("script");
26620 // more advanced tabs, built from javascript
26621 var jtabs = new Roo.TabPanel("jtabs");
26622 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26624 // set up the UpdateManager
26625 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26626 var updater = tab2.getUpdateManager();
26627 updater.setDefaultUrl("ajax1.htm");
26628 tab2.on('activate', updater.refresh, updater, true);
26630 // Use setUrl for Ajax loading
26631 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26632 tab3.setUrl("ajax2.htm", null, true);
26635 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26638 jtabs.activate("jtabs-1");
26641 * Create a new TabPanel.
26642 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26643 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26645 Roo.TabPanel = function(container, config){
26647 * The container element for this TabPanel.
26648 * @type Roo.Element
26650 this.el = Roo.get(container, true);
26652 if(typeof config == "boolean"){
26653 this.tabPosition = config ? "bottom" : "top";
26655 Roo.apply(this, config);
26658 if(this.tabPosition == "bottom"){
26659 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26660 this.el.addClass("x-tabs-bottom");
26662 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26663 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26664 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26666 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26668 if(this.tabPosition != "bottom"){
26669 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26670 * @type Roo.Element
26672 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26673 this.el.addClass("x-tabs-top");
26677 this.bodyEl.setStyle("position", "relative");
26679 this.active = null;
26680 this.activateDelegate = this.activate.createDelegate(this);
26685 * Fires when the active tab changes
26686 * @param {Roo.TabPanel} this
26687 * @param {Roo.TabPanelItem} activePanel The new active tab
26691 * @event beforetabchange
26692 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26693 * @param {Roo.TabPanel} this
26694 * @param {Object} e Set cancel to true on this object to cancel the tab change
26695 * @param {Roo.TabPanelItem} tab The tab being changed to
26697 "beforetabchange" : true
26700 Roo.EventManager.onWindowResize(this.onResize, this);
26701 this.cpad = this.el.getPadding("lr");
26702 this.hiddenCount = 0;
26705 // toolbar on the tabbar support...
26706 if (this.toolbar) {
26707 var tcfg = this.toolbar;
26708 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26709 this.toolbar = new Roo.Toolbar(tcfg);
26710 if (Roo.isSafari) {
26711 var tbl = tcfg.container.child('table', true);
26712 tbl.setAttribute('width', '100%');
26719 Roo.TabPanel.superclass.constructor.call(this);
26722 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26724 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26726 tabPosition : "top",
26728 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26730 currentTabWidth : 0,
26732 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26736 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26740 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26742 preferredTabWidth : 175,
26744 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26746 resizeTabs : false,
26748 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26750 monitorResize : true,
26752 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26757 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26758 * @param {String} id The id of the div to use <b>or create</b>
26759 * @param {String} text The text for the tab
26760 * @param {String} content (optional) Content to put in the TabPanelItem body
26761 * @param {Boolean} closable (optional) True to create a close icon on the tab
26762 * @return {Roo.TabPanelItem} The created TabPanelItem
26764 addTab : function(id, text, content, closable){
26765 var item = new Roo.TabPanelItem(this, id, text, closable);
26766 this.addTabItem(item);
26768 item.setContent(content);
26774 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26775 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26776 * @return {Roo.TabPanelItem}
26778 getTab : function(id){
26779 return this.items[id];
26783 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26784 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26786 hideTab : function(id){
26787 var t = this.items[id];
26790 this.hiddenCount++;
26791 this.autoSizeTabs();
26796 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26797 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26799 unhideTab : function(id){
26800 var t = this.items[id];
26802 t.setHidden(false);
26803 this.hiddenCount--;
26804 this.autoSizeTabs();
26809 * Adds an existing {@link Roo.TabPanelItem}.
26810 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26812 addTabItem : function(item){
26813 this.items[item.id] = item;
26814 this.items.push(item);
26815 if(this.resizeTabs){
26816 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26817 this.autoSizeTabs();
26824 * Removes a {@link Roo.TabPanelItem}.
26825 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26827 removeTab : function(id){
26828 var items = this.items;
26829 var tab = items[id];
26830 if(!tab) { return; }
26831 var index = items.indexOf(tab);
26832 if(this.active == tab && items.length > 1){
26833 var newTab = this.getNextAvailable(index);
26838 this.stripEl.dom.removeChild(tab.pnode.dom);
26839 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26840 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26842 items.splice(index, 1);
26843 delete this.items[tab.id];
26844 tab.fireEvent("close", tab);
26845 tab.purgeListeners();
26846 this.autoSizeTabs();
26849 getNextAvailable : function(start){
26850 var items = this.items;
26852 // look for a next tab that will slide over to
26853 // replace the one being removed
26854 while(index < items.length){
26855 var item = items[++index];
26856 if(item && !item.isHidden()){
26860 // if one isn't found select the previous tab (on the left)
26863 var item = items[--index];
26864 if(item && !item.isHidden()){
26872 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26873 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26875 disableTab : function(id){
26876 var tab = this.items[id];
26877 if(tab && this.active != tab){
26883 * Enables a {@link Roo.TabPanelItem} that is disabled.
26884 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26886 enableTab : function(id){
26887 var tab = this.items[id];
26892 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26893 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26894 * @return {Roo.TabPanelItem} The TabPanelItem.
26896 activate : function(id){
26897 var tab = this.items[id];
26901 if(tab == this.active || tab.disabled){
26905 this.fireEvent("beforetabchange", this, e, tab);
26906 if(e.cancel !== true && !tab.disabled){
26908 this.active.hide();
26910 this.active = this.items[id];
26911 this.active.show();
26912 this.fireEvent("tabchange", this, this.active);
26918 * Gets the active {@link Roo.TabPanelItem}.
26919 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26921 getActiveTab : function(){
26922 return this.active;
26926 * Updates the tab body element to fit the height of the container element
26927 * for overflow scrolling
26928 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26930 syncHeight : function(targetHeight){
26931 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26932 var bm = this.bodyEl.getMargins();
26933 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26934 this.bodyEl.setHeight(newHeight);
26938 onResize : function(){
26939 if(this.monitorResize){
26940 this.autoSizeTabs();
26945 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26947 beginUpdate : function(){
26948 this.updating = true;
26952 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26954 endUpdate : function(){
26955 this.updating = false;
26956 this.autoSizeTabs();
26960 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26962 autoSizeTabs : function(){
26963 var count = this.items.length;
26964 var vcount = count - this.hiddenCount;
26965 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26966 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26967 var availWidth = Math.floor(w / vcount);
26968 var b = this.stripBody;
26969 if(b.getWidth() > w){
26970 var tabs = this.items;
26971 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26972 if(availWidth < this.minTabWidth){
26973 /*if(!this.sleft){ // incomplete scrolling code
26974 this.createScrollButtons();
26977 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26980 if(this.currentTabWidth < this.preferredTabWidth){
26981 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26987 * Returns the number of tabs in this TabPanel.
26990 getCount : function(){
26991 return this.items.length;
26995 * Resizes all the tabs to the passed width
26996 * @param {Number} The new width
26998 setTabWidth : function(width){
26999 this.currentTabWidth = width;
27000 for(var i = 0, len = this.items.length; i < len; i++) {
27001 if(!this.items[i].isHidden())this.items[i].setWidth(width);
27006 * Destroys this TabPanel
27007 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
27009 destroy : function(removeEl){
27010 Roo.EventManager.removeResizeListener(this.onResize, this);
27011 for(var i = 0, len = this.items.length; i < len; i++){
27012 this.items[i].purgeListeners();
27014 if(removeEl === true){
27015 this.el.update("");
27022 * @class Roo.TabPanelItem
27023 * @extends Roo.util.Observable
27024 * Represents an individual item (tab plus body) in a TabPanel.
27025 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
27026 * @param {String} id The id of this TabPanelItem
27027 * @param {String} text The text for the tab of this TabPanelItem
27028 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
27030 Roo.TabPanelItem = function(tabPanel, id, text, closable){
27032 * The {@link Roo.TabPanel} this TabPanelItem belongs to
27033 * @type Roo.TabPanel
27035 this.tabPanel = tabPanel;
27037 * The id for this TabPanelItem
27042 this.disabled = false;
27046 this.loaded = false;
27047 this.closable = closable;
27050 * The body element for this TabPanelItem.
27051 * @type Roo.Element
27053 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27054 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27055 this.bodyEl.setStyle("display", "block");
27056 this.bodyEl.setStyle("zoom", "1");
27059 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27061 this.el = Roo.get(els.el, true);
27062 this.inner = Roo.get(els.inner, true);
27063 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27064 this.pnode = Roo.get(els.el.parentNode, true);
27065 this.el.on("mousedown", this.onTabMouseDown, this);
27066 this.el.on("click", this.onTabClick, this);
27069 var c = Roo.get(els.close, true);
27070 c.dom.title = this.closeText;
27071 c.addClassOnOver("close-over");
27072 c.on("click", this.closeClick, this);
27078 * Fires when this tab becomes the active tab.
27079 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27080 * @param {Roo.TabPanelItem} this
27084 * @event beforeclose
27085 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27086 * @param {Roo.TabPanelItem} this
27087 * @param {Object} e Set cancel to true on this object to cancel the close.
27089 "beforeclose": true,
27092 * Fires when this tab is closed.
27093 * @param {Roo.TabPanelItem} this
27097 * @event deactivate
27098 * Fires when this tab is no longer the active tab.
27099 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27100 * @param {Roo.TabPanelItem} this
27102 "deactivate" : true
27104 this.hidden = false;
27106 Roo.TabPanelItem.superclass.constructor.call(this);
27109 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27110 purgeListeners : function(){
27111 Roo.util.Observable.prototype.purgeListeners.call(this);
27112 this.el.removeAllListeners();
27115 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27118 this.pnode.addClass("on");
27121 this.tabPanel.stripWrap.repaint();
27123 this.fireEvent("activate", this.tabPanel, this);
27127 * Returns true if this tab is the active tab.
27128 * @return {Boolean}
27130 isActive : function(){
27131 return this.tabPanel.getActiveTab() == this;
27135 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27138 this.pnode.removeClass("on");
27140 this.fireEvent("deactivate", this.tabPanel, this);
27143 hideAction : function(){
27144 this.bodyEl.hide();
27145 this.bodyEl.setStyle("position", "absolute");
27146 this.bodyEl.setLeft("-20000px");
27147 this.bodyEl.setTop("-20000px");
27150 showAction : function(){
27151 this.bodyEl.setStyle("position", "relative");
27152 this.bodyEl.setTop("");
27153 this.bodyEl.setLeft("");
27154 this.bodyEl.show();
27158 * Set the tooltip for the tab.
27159 * @param {String} tooltip The tab's tooltip
27161 setTooltip : function(text){
27162 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27163 this.textEl.dom.qtip = text;
27164 this.textEl.dom.removeAttribute('title');
27166 this.textEl.dom.title = text;
27170 onTabClick : function(e){
27171 e.preventDefault();
27172 this.tabPanel.activate(this.id);
27175 onTabMouseDown : function(e){
27176 e.preventDefault();
27177 this.tabPanel.activate(this.id);
27180 getWidth : function(){
27181 return this.inner.getWidth();
27184 setWidth : function(width){
27185 var iwidth = width - this.pnode.getPadding("lr");
27186 this.inner.setWidth(iwidth);
27187 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27188 this.pnode.setWidth(width);
27192 * Show or hide the tab
27193 * @param {Boolean} hidden True to hide or false to show.
27195 setHidden : function(hidden){
27196 this.hidden = hidden;
27197 this.pnode.setStyle("display", hidden ? "none" : "");
27201 * Returns true if this tab is "hidden"
27202 * @return {Boolean}
27204 isHidden : function(){
27205 return this.hidden;
27209 * Returns the text for this tab
27212 getText : function(){
27216 autoSize : function(){
27217 //this.el.beginMeasure();
27218 this.textEl.setWidth(1);
27220 * #2804 [new] Tabs in Roojs
27221 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27223 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27224 //this.el.endMeasure();
27228 * Sets the text for the tab (Note: this also sets the tooltip text)
27229 * @param {String} text The tab's text and tooltip
27231 setText : function(text){
27233 this.textEl.update(text);
27234 this.setTooltip(text);
27235 if(!this.tabPanel.resizeTabs){
27240 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27242 activate : function(){
27243 this.tabPanel.activate(this.id);
27247 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27249 disable : function(){
27250 if(this.tabPanel.active != this){
27251 this.disabled = true;
27252 this.pnode.addClass("disabled");
27257 * Enables this TabPanelItem if it was previously disabled.
27259 enable : function(){
27260 this.disabled = false;
27261 this.pnode.removeClass("disabled");
27265 * Sets the content for this TabPanelItem.
27266 * @param {String} content The content
27267 * @param {Boolean} loadScripts true to look for and load scripts
27269 setContent : function(content, loadScripts){
27270 this.bodyEl.update(content, loadScripts);
27274 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27275 * @return {Roo.UpdateManager} The UpdateManager
27277 getUpdateManager : function(){
27278 return this.bodyEl.getUpdateManager();
27282 * Set a URL to be used to load the content for this TabPanelItem.
27283 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27284 * @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)
27285 * @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)
27286 * @return {Roo.UpdateManager} The UpdateManager
27288 setUrl : function(url, params, loadOnce){
27289 if(this.refreshDelegate){
27290 this.un('activate', this.refreshDelegate);
27292 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27293 this.on("activate", this.refreshDelegate);
27294 return this.bodyEl.getUpdateManager();
27298 _handleRefresh : function(url, params, loadOnce){
27299 if(!loadOnce || !this.loaded){
27300 var updater = this.bodyEl.getUpdateManager();
27301 updater.update(url, params, this._setLoaded.createDelegate(this));
27306 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27307 * Will fail silently if the setUrl method has not been called.
27308 * This does not activate the panel, just updates its content.
27310 refresh : function(){
27311 if(this.refreshDelegate){
27312 this.loaded = false;
27313 this.refreshDelegate();
27318 _setLoaded : function(){
27319 this.loaded = true;
27323 closeClick : function(e){
27326 this.fireEvent("beforeclose", this, o);
27327 if(o.cancel !== true){
27328 this.tabPanel.removeTab(this.id);
27332 * The text displayed in the tooltip for the close icon.
27335 closeText : "Close this tab"
27339 Roo.TabPanel.prototype.createStrip = function(container){
27340 var strip = document.createElement("div");
27341 strip.className = "x-tabs-wrap";
27342 container.appendChild(strip);
27346 Roo.TabPanel.prototype.createStripList = function(strip){
27347 // div wrapper for retard IE
27348 // returns the "tr" element.
27349 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27350 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27351 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27352 return strip.firstChild.firstChild.firstChild.firstChild;
27355 Roo.TabPanel.prototype.createBody = function(container){
27356 var body = document.createElement("div");
27357 Roo.id(body, "tab-body");
27358 Roo.fly(body).addClass("x-tabs-body");
27359 container.appendChild(body);
27363 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27364 var body = Roo.getDom(id);
27366 body = document.createElement("div");
27369 Roo.fly(body).addClass("x-tabs-item-body");
27370 bodyEl.insertBefore(body, bodyEl.firstChild);
27374 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27375 var td = document.createElement("td");
27376 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27377 //stripEl.appendChild(td);
27379 td.className = "x-tabs-closable";
27380 if(!this.closeTpl){
27381 this.closeTpl = new Roo.Template(
27382 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27383 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27384 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27387 var el = this.closeTpl.overwrite(td, {"text": text});
27388 var close = el.getElementsByTagName("div")[0];
27389 var inner = el.getElementsByTagName("em")[0];
27390 return {"el": el, "close": close, "inner": inner};
27393 this.tabTpl = new Roo.Template(
27394 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27395 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27398 var el = this.tabTpl.overwrite(td, {"text": text});
27399 var inner = el.getElementsByTagName("em")[0];
27400 return {"el": el, "inner": inner};
27404 * Ext JS Library 1.1.1
27405 * Copyright(c) 2006-2007, Ext JS, LLC.
27407 * Originally Released Under LGPL - original licence link has changed is not relivant.
27410 * <script type="text/javascript">
27414 * @class Roo.Button
27415 * @extends Roo.util.Observable
27416 * Simple Button class
27417 * @cfg {String} text The button text
27418 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27419 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27420 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27421 * @cfg {Object} scope The scope of the handler
27422 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27423 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27424 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27425 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27426 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27427 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27428 applies if enableToggle = true)
27429 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27430 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27431 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27433 * Create a new button
27434 * @param {Object} config The config object
27436 Roo.Button = function(renderTo, config)
27440 renderTo = config.renderTo || false;
27443 Roo.apply(this, config);
27447 * Fires when this button is clicked
27448 * @param {Button} this
27449 * @param {EventObject} e The click event
27454 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27455 * @param {Button} this
27456 * @param {Boolean} pressed
27461 * Fires when the mouse hovers over the button
27462 * @param {Button} this
27463 * @param {Event} e The event object
27465 'mouseover' : true,
27468 * Fires when the mouse exits the button
27469 * @param {Button} this
27470 * @param {Event} e The event object
27475 * Fires when the button is rendered
27476 * @param {Button} this
27481 this.menu = Roo.menu.MenuMgr.get(this.menu);
27483 // register listeners first!! - so render can be captured..
27484 Roo.util.Observable.call(this);
27486 this.render(renderTo);
27492 Roo.extend(Roo.Button, Roo.util.Observable, {
27498 * Read-only. True if this button is hidden
27503 * Read-only. True if this button is disabled
27508 * Read-only. True if this button is pressed (only if enableToggle = true)
27514 * @cfg {Number} tabIndex
27515 * The DOM tabIndex for this button (defaults to undefined)
27517 tabIndex : undefined,
27520 * @cfg {Boolean} enableToggle
27521 * True to enable pressed/not pressed toggling (defaults to false)
27523 enableToggle: false,
27525 * @cfg {Mixed} menu
27526 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27530 * @cfg {String} menuAlign
27531 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27533 menuAlign : "tl-bl?",
27536 * @cfg {String} iconCls
27537 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27539 iconCls : undefined,
27541 * @cfg {String} type
27542 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27547 menuClassTarget: 'tr',
27550 * @cfg {String} clickEvent
27551 * The type of event to map to the button's event handler (defaults to 'click')
27553 clickEvent : 'click',
27556 * @cfg {Boolean} handleMouseEvents
27557 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27559 handleMouseEvents : true,
27562 * @cfg {String} tooltipType
27563 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27565 tooltipType : 'qtip',
27568 * @cfg {String} cls
27569 * A CSS class to apply to the button's main element.
27573 * @cfg {Roo.Template} template (Optional)
27574 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27575 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27576 * require code modifications if required elements (e.g. a button) aren't present.
27580 render : function(renderTo){
27582 if(this.hideParent){
27583 this.parentEl = Roo.get(renderTo);
27585 if(!this.dhconfig){
27586 if(!this.template){
27587 if(!Roo.Button.buttonTemplate){
27588 // hideous table template
27589 Roo.Button.buttonTemplate = new Roo.Template(
27590 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27591 '<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>',
27592 "</tr></tbody></table>");
27594 this.template = Roo.Button.buttonTemplate;
27596 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27597 var btnEl = btn.child("button:first");
27598 btnEl.on('focus', this.onFocus, this);
27599 btnEl.on('blur', this.onBlur, this);
27601 btn.addClass(this.cls);
27604 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27607 btnEl.addClass(this.iconCls);
27609 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27612 if(this.tabIndex !== undefined){
27613 btnEl.dom.tabIndex = this.tabIndex;
27616 if(typeof this.tooltip == 'object'){
27617 Roo.QuickTips.tips(Roo.apply({
27621 btnEl.dom[this.tooltipType] = this.tooltip;
27625 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27629 this.el.dom.id = this.el.id = this.id;
27632 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27633 this.menu.on("show", this.onMenuShow, this);
27634 this.menu.on("hide", this.onMenuHide, this);
27636 btn.addClass("x-btn");
27637 if(Roo.isIE && !Roo.isIE7){
27638 this.autoWidth.defer(1, this);
27642 if(this.handleMouseEvents){
27643 btn.on("mouseover", this.onMouseOver, this);
27644 btn.on("mouseout", this.onMouseOut, this);
27645 btn.on("mousedown", this.onMouseDown, this);
27647 btn.on(this.clickEvent, this.onClick, this);
27648 //btn.on("mouseup", this.onMouseUp, this);
27655 Roo.ButtonToggleMgr.register(this);
27657 this.el.addClass("x-btn-pressed");
27660 var repeater = new Roo.util.ClickRepeater(btn,
27661 typeof this.repeat == "object" ? this.repeat : {}
27663 repeater.on("click", this.onClick, this);
27666 this.fireEvent('render', this);
27670 * Returns the button's underlying element
27671 * @return {Roo.Element} The element
27673 getEl : function(){
27678 * Destroys this Button and removes any listeners.
27680 destroy : function(){
27681 Roo.ButtonToggleMgr.unregister(this);
27682 this.el.removeAllListeners();
27683 this.purgeListeners();
27688 autoWidth : function(){
27690 this.el.setWidth("auto");
27691 if(Roo.isIE7 && Roo.isStrict){
27692 var ib = this.el.child('button');
27693 if(ib && ib.getWidth() > 20){
27695 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27700 this.el.beginMeasure();
27702 if(this.el.getWidth() < this.minWidth){
27703 this.el.setWidth(this.minWidth);
27706 this.el.endMeasure();
27713 * Assigns this button's click handler
27714 * @param {Function} handler The function to call when the button is clicked
27715 * @param {Object} scope (optional) Scope for the function passed in
27717 setHandler : function(handler, scope){
27718 this.handler = handler;
27719 this.scope = scope;
27723 * Sets this button's text
27724 * @param {String} text The button text
27726 setText : function(text){
27729 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27735 * Gets the text for this button
27736 * @return {String} The button text
27738 getText : function(){
27746 this.hidden = false;
27748 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27756 this.hidden = true;
27758 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27763 * Convenience function for boolean show/hide
27764 * @param {Boolean} visible True to show, false to hide
27766 setVisible: function(visible){
27775 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27776 * @param {Boolean} state (optional) Force a particular state
27778 toggle : function(state){
27779 state = state === undefined ? !this.pressed : state;
27780 if(state != this.pressed){
27782 this.el.addClass("x-btn-pressed");
27783 this.pressed = true;
27784 this.fireEvent("toggle", this, true);
27786 this.el.removeClass("x-btn-pressed");
27787 this.pressed = false;
27788 this.fireEvent("toggle", this, false);
27790 if(this.toggleHandler){
27791 this.toggleHandler.call(this.scope || this, this, state);
27799 focus : function(){
27800 this.el.child('button:first').focus();
27804 * Disable this button
27806 disable : function(){
27808 this.el.addClass("x-btn-disabled");
27810 this.disabled = true;
27814 * Enable this button
27816 enable : function(){
27818 this.el.removeClass("x-btn-disabled");
27820 this.disabled = false;
27824 * Convenience function for boolean enable/disable
27825 * @param {Boolean} enabled True to enable, false to disable
27827 setDisabled : function(v){
27828 this[v !== true ? "enable" : "disable"]();
27832 onClick : function(e){
27834 e.preventDefault();
27839 if(!this.disabled){
27840 if(this.enableToggle){
27843 if(this.menu && !this.menu.isVisible()){
27844 this.menu.show(this.el, this.menuAlign);
27846 this.fireEvent("click", this, e);
27848 this.el.removeClass("x-btn-over");
27849 this.handler.call(this.scope || this, this, e);
27854 onMouseOver : function(e){
27855 if(!this.disabled){
27856 this.el.addClass("x-btn-over");
27857 this.fireEvent('mouseover', this, e);
27861 onMouseOut : function(e){
27862 if(!e.within(this.el, true)){
27863 this.el.removeClass("x-btn-over");
27864 this.fireEvent('mouseout', this, e);
27868 onFocus : function(e){
27869 if(!this.disabled){
27870 this.el.addClass("x-btn-focus");
27874 onBlur : function(e){
27875 this.el.removeClass("x-btn-focus");
27878 onMouseDown : function(e){
27879 if(!this.disabled && e.button == 0){
27880 this.el.addClass("x-btn-click");
27881 Roo.get(document).on('mouseup', this.onMouseUp, this);
27885 onMouseUp : function(e){
27887 this.el.removeClass("x-btn-click");
27888 Roo.get(document).un('mouseup', this.onMouseUp, this);
27892 onMenuShow : function(e){
27893 this.el.addClass("x-btn-menu-active");
27896 onMenuHide : function(e){
27897 this.el.removeClass("x-btn-menu-active");
27901 // Private utility class used by Button
27902 Roo.ButtonToggleMgr = function(){
27905 function toggleGroup(btn, state){
27907 var g = groups[btn.toggleGroup];
27908 for(var i = 0, l = g.length; i < l; i++){
27910 g[i].toggle(false);
27917 register : function(btn){
27918 if(!btn.toggleGroup){
27921 var g = groups[btn.toggleGroup];
27923 g = groups[btn.toggleGroup] = [];
27926 btn.on("toggle", toggleGroup);
27929 unregister : function(btn){
27930 if(!btn.toggleGroup){
27933 var g = groups[btn.toggleGroup];
27936 btn.un("toggle", toggleGroup);
27942 * Ext JS Library 1.1.1
27943 * Copyright(c) 2006-2007, Ext JS, LLC.
27945 * Originally Released Under LGPL - original licence link has changed is not relivant.
27948 * <script type="text/javascript">
27952 * @class Roo.SplitButton
27953 * @extends Roo.Button
27954 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27955 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27956 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27957 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27958 * @cfg {String} arrowTooltip The title attribute of the arrow
27960 * Create a new menu button
27961 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27962 * @param {Object} config The config object
27964 Roo.SplitButton = function(renderTo, config){
27965 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27967 * @event arrowclick
27968 * Fires when this button's arrow is clicked
27969 * @param {SplitButton} this
27970 * @param {EventObject} e The click event
27972 this.addEvents({"arrowclick":true});
27975 Roo.extend(Roo.SplitButton, Roo.Button, {
27976 render : function(renderTo){
27977 // this is one sweet looking template!
27978 var tpl = new Roo.Template(
27979 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27980 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27981 '<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>',
27982 "</tbody></table></td><td>",
27983 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27984 '<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>',
27985 "</tbody></table></td></tr></table>"
27987 var btn = tpl.append(renderTo, [this.text, this.type], true);
27988 var btnEl = btn.child("button");
27990 btn.addClass(this.cls);
27993 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27996 btnEl.addClass(this.iconCls);
27998 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
28002 if(this.handleMouseEvents){
28003 btn.on("mouseover", this.onMouseOver, this);
28004 btn.on("mouseout", this.onMouseOut, this);
28005 btn.on("mousedown", this.onMouseDown, this);
28006 btn.on("mouseup", this.onMouseUp, this);
28008 btn.on(this.clickEvent, this.onClick, this);
28010 if(typeof this.tooltip == 'object'){
28011 Roo.QuickTips.tips(Roo.apply({
28015 btnEl.dom[this.tooltipType] = this.tooltip;
28018 if(this.arrowTooltip){
28019 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
28028 this.el.addClass("x-btn-pressed");
28030 if(Roo.isIE && !Roo.isIE7){
28031 this.autoWidth.defer(1, this);
28036 this.menu.on("show", this.onMenuShow, this);
28037 this.menu.on("hide", this.onMenuHide, this);
28039 this.fireEvent('render', this);
28043 autoWidth : function(){
28045 var tbl = this.el.child("table:first");
28046 var tbl2 = this.el.child("table:last");
28047 this.el.setWidth("auto");
28048 tbl.setWidth("auto");
28049 if(Roo.isIE7 && Roo.isStrict){
28050 var ib = this.el.child('button:first');
28051 if(ib && ib.getWidth() > 20){
28053 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28058 this.el.beginMeasure();
28060 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28061 tbl.setWidth(this.minWidth-tbl2.getWidth());
28064 this.el.endMeasure();
28067 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28071 * Sets this button's click handler
28072 * @param {Function} handler The function to call when the button is clicked
28073 * @param {Object} scope (optional) Scope for the function passed above
28075 setHandler : function(handler, scope){
28076 this.handler = handler;
28077 this.scope = scope;
28081 * Sets this button's arrow click handler
28082 * @param {Function} handler The function to call when the arrow is clicked
28083 * @param {Object} scope (optional) Scope for the function passed above
28085 setArrowHandler : function(handler, scope){
28086 this.arrowHandler = handler;
28087 this.scope = scope;
28093 focus : function(){
28095 this.el.child("button:first").focus();
28100 onClick : function(e){
28101 e.preventDefault();
28102 if(!this.disabled){
28103 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28104 if(this.menu && !this.menu.isVisible()){
28105 this.menu.show(this.el, this.menuAlign);
28107 this.fireEvent("arrowclick", this, e);
28108 if(this.arrowHandler){
28109 this.arrowHandler.call(this.scope || this, this, e);
28112 this.fireEvent("click", this, e);
28114 this.handler.call(this.scope || this, this, e);
28120 onMouseDown : function(e){
28121 if(!this.disabled){
28122 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28126 onMouseUp : function(e){
28127 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28132 // backwards compat
28133 Roo.MenuButton = Roo.SplitButton;/*
28135 * Ext JS Library 1.1.1
28136 * Copyright(c) 2006-2007, Ext JS, LLC.
28138 * Originally Released Under LGPL - original licence link has changed is not relivant.
28141 * <script type="text/javascript">
28145 * @class Roo.Toolbar
28146 * Basic Toolbar class.
28148 * Creates a new Toolbar
28149 * @param {Object} container The config object
28151 Roo.Toolbar = function(container, buttons, config)
28153 /// old consturctor format still supported..
28154 if(container instanceof Array){ // omit the container for later rendering
28155 buttons = container;
28159 if (typeof(container) == 'object' && container.xtype) {
28160 config = container;
28161 container = config.container;
28162 buttons = config.buttons || []; // not really - use items!!
28165 if (config && config.items) {
28166 xitems = config.items;
28167 delete config.items;
28169 Roo.apply(this, config);
28170 this.buttons = buttons;
28173 this.render(container);
28175 this.xitems = xitems;
28176 Roo.each(xitems, function(b) {
28182 Roo.Toolbar.prototype = {
28184 * @cfg {Array} items
28185 * array of button configs or elements to add (will be converted to a MixedCollection)
28189 * @cfg {String/HTMLElement/Element} container
28190 * The id or element that will contain the toolbar
28193 render : function(ct){
28194 this.el = Roo.get(ct);
28196 this.el.addClass(this.cls);
28198 // using a table allows for vertical alignment
28199 // 100% width is needed by Safari...
28200 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28201 this.tr = this.el.child("tr", true);
28203 this.items = new Roo.util.MixedCollection(false, function(o){
28204 return o.id || ("item" + (++autoId));
28207 this.add.apply(this, this.buttons);
28208 delete this.buttons;
28213 * Adds element(s) to the toolbar -- this function takes a variable number of
28214 * arguments of mixed type and adds them to the toolbar.
28215 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28217 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28218 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28219 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28220 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28221 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28222 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28223 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28224 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28225 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28227 * @param {Mixed} arg2
28228 * @param {Mixed} etc.
28231 var a = arguments, l = a.length;
28232 for(var i = 0; i < l; i++){
28237 _add : function(el) {
28240 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28243 if (el.applyTo){ // some kind of form field
28244 return this.addField(el);
28246 if (el.render){ // some kind of Toolbar.Item
28247 return this.addItem(el);
28249 if (typeof el == "string"){ // string
28250 if(el == "separator" || el == "-"){
28251 return this.addSeparator();
28254 return this.addSpacer();
28257 return this.addFill();
28259 return this.addText(el);
28262 if(el.tagName){ // element
28263 return this.addElement(el);
28265 if(typeof el == "object"){ // must be button config?
28266 return this.addButton(el);
28268 // and now what?!?!
28274 * Add an Xtype element
28275 * @param {Object} xtype Xtype Object
28276 * @return {Object} created Object
28278 addxtype : function(e){
28279 return this.add(e);
28283 * Returns the Element for this toolbar.
28284 * @return {Roo.Element}
28286 getEl : function(){
28292 * @return {Roo.Toolbar.Item} The separator item
28294 addSeparator : function(){
28295 return this.addItem(new Roo.Toolbar.Separator());
28299 * Adds a spacer element
28300 * @return {Roo.Toolbar.Spacer} The spacer item
28302 addSpacer : function(){
28303 return this.addItem(new Roo.Toolbar.Spacer());
28307 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28308 * @return {Roo.Toolbar.Fill} The fill item
28310 addFill : function(){
28311 return this.addItem(new Roo.Toolbar.Fill());
28315 * Adds any standard HTML element to the toolbar
28316 * @param {String/HTMLElement/Element} el The element or id of the element to add
28317 * @return {Roo.Toolbar.Item} The element's item
28319 addElement : function(el){
28320 return this.addItem(new Roo.Toolbar.Item(el));
28323 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28324 * @type Roo.util.MixedCollection
28329 * Adds any Toolbar.Item or subclass
28330 * @param {Roo.Toolbar.Item} item
28331 * @return {Roo.Toolbar.Item} The item
28333 addItem : function(item){
28334 var td = this.nextBlock();
28336 this.items.add(item);
28341 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28342 * @param {Object/Array} config A button config or array of configs
28343 * @return {Roo.Toolbar.Button/Array}
28345 addButton : function(config){
28346 if(config instanceof Array){
28348 for(var i = 0, len = config.length; i < len; i++) {
28349 buttons.push(this.addButton(config[i]));
28354 if(!(config instanceof Roo.Toolbar.Button)){
28356 new Roo.Toolbar.SplitButton(config) :
28357 new Roo.Toolbar.Button(config);
28359 var td = this.nextBlock();
28366 * Adds text to the toolbar
28367 * @param {String} text The text to add
28368 * @return {Roo.Toolbar.Item} The element's item
28370 addText : function(text){
28371 return this.addItem(new Roo.Toolbar.TextItem(text));
28375 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28376 * @param {Number} index The index where the item is to be inserted
28377 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28378 * @return {Roo.Toolbar.Button/Item}
28380 insertButton : function(index, item){
28381 if(item instanceof Array){
28383 for(var i = 0, len = item.length; i < len; i++) {
28384 buttons.push(this.insertButton(index + i, item[i]));
28388 if (!(item instanceof Roo.Toolbar.Button)){
28389 item = new Roo.Toolbar.Button(item);
28391 var td = document.createElement("td");
28392 this.tr.insertBefore(td, this.tr.childNodes[index]);
28394 this.items.insert(index, item);
28399 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28400 * @param {Object} config
28401 * @return {Roo.Toolbar.Item} The element's item
28403 addDom : function(config, returnEl){
28404 var td = this.nextBlock();
28405 Roo.DomHelper.overwrite(td, config);
28406 var ti = new Roo.Toolbar.Item(td.firstChild);
28408 this.items.add(ti);
28413 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28414 * @type Roo.util.MixedCollection
28419 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28420 * Note: the field should not have been rendered yet. For a field that has already been
28421 * rendered, use {@link #addElement}.
28422 * @param {Roo.form.Field} field
28423 * @return {Roo.ToolbarItem}
28427 addField : function(field) {
28428 if (!this.fields) {
28430 this.fields = new Roo.util.MixedCollection(false, function(o){
28431 return o.id || ("item" + (++autoId));
28436 var td = this.nextBlock();
28438 var ti = new Roo.Toolbar.Item(td.firstChild);
28440 this.items.add(ti);
28441 this.fields.add(field);
28452 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28453 this.el.child('div').hide();
28461 this.el.child('div').show();
28465 nextBlock : function(){
28466 var td = document.createElement("td");
28467 this.tr.appendChild(td);
28472 destroy : function(){
28473 if(this.items){ // rendered?
28474 Roo.destroy.apply(Roo, this.items.items);
28476 if(this.fields){ // rendered?
28477 Roo.destroy.apply(Roo, this.fields.items);
28479 Roo.Element.uncache(this.el, this.tr);
28484 * @class Roo.Toolbar.Item
28485 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28487 * Creates a new Item
28488 * @param {HTMLElement} el
28490 Roo.Toolbar.Item = function(el){
28491 this.el = Roo.getDom(el);
28492 this.id = Roo.id(this.el);
28493 this.hidden = false;
28496 Roo.Toolbar.Item.prototype = {
28499 * Get this item's HTML Element
28500 * @return {HTMLElement}
28502 getEl : function(){
28507 render : function(td){
28509 td.appendChild(this.el);
28513 * Removes and destroys this item.
28515 destroy : function(){
28516 this.td.parentNode.removeChild(this.td);
28523 this.hidden = false;
28524 this.td.style.display = "";
28531 this.hidden = true;
28532 this.td.style.display = "none";
28536 * Convenience function for boolean show/hide.
28537 * @param {Boolean} visible true to show/false to hide
28539 setVisible: function(visible){
28548 * Try to focus this item.
28550 focus : function(){
28551 Roo.fly(this.el).focus();
28555 * Disables this item.
28557 disable : function(){
28558 Roo.fly(this.td).addClass("x-item-disabled");
28559 this.disabled = true;
28560 this.el.disabled = true;
28564 * Enables this item.
28566 enable : function(){
28567 Roo.fly(this.td).removeClass("x-item-disabled");
28568 this.disabled = false;
28569 this.el.disabled = false;
28575 * @class Roo.Toolbar.Separator
28576 * @extends Roo.Toolbar.Item
28577 * A simple toolbar separator class
28579 * Creates a new Separator
28581 Roo.Toolbar.Separator = function(){
28582 var s = document.createElement("span");
28583 s.className = "ytb-sep";
28584 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
28586 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28587 enable:Roo.emptyFn,
28588 disable:Roo.emptyFn,
28593 * @class Roo.Toolbar.Spacer
28594 * @extends Roo.Toolbar.Item
28595 * A simple element that adds extra horizontal space to a toolbar.
28597 * Creates a new Spacer
28599 Roo.Toolbar.Spacer = function(){
28600 var s = document.createElement("div");
28601 s.className = "ytb-spacer";
28602 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
28604 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28605 enable:Roo.emptyFn,
28606 disable:Roo.emptyFn,
28611 * @class Roo.Toolbar.Fill
28612 * @extends Roo.Toolbar.Spacer
28613 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28615 * Creates a new Spacer
28617 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28619 render : function(td){
28620 td.style.width = '100%';
28621 Roo.Toolbar.Fill.superclass.render.call(this, td);
28626 * @class Roo.Toolbar.TextItem
28627 * @extends Roo.Toolbar.Item
28628 * A simple class that renders text directly into a toolbar.
28630 * Creates a new TextItem
28631 * @param {String} text
28633 Roo.Toolbar.TextItem = function(text){
28634 if (typeof(text) == 'object') {
28637 var s = document.createElement("span");
28638 s.className = "ytb-text";
28639 s.innerHTML = text;
28640 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28642 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28643 enable:Roo.emptyFn,
28644 disable:Roo.emptyFn,
28649 * @class Roo.Toolbar.Button
28650 * @extends Roo.Button
28651 * A button that renders into a toolbar.
28653 * Creates a new Button
28654 * @param {Object} config A standard {@link Roo.Button} config object
28656 Roo.Toolbar.Button = function(config){
28657 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28659 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28660 render : function(td){
28662 Roo.Toolbar.Button.superclass.render.call(this, td);
28666 * Removes and destroys this button
28668 destroy : function(){
28669 Roo.Toolbar.Button.superclass.destroy.call(this);
28670 this.td.parentNode.removeChild(this.td);
28674 * Shows this button
28677 this.hidden = false;
28678 this.td.style.display = "";
28682 * Hides this button
28685 this.hidden = true;
28686 this.td.style.display = "none";
28690 * Disables this item
28692 disable : function(){
28693 Roo.fly(this.td).addClass("x-item-disabled");
28694 this.disabled = true;
28698 * Enables this item
28700 enable : function(){
28701 Roo.fly(this.td).removeClass("x-item-disabled");
28702 this.disabled = false;
28705 // backwards compat
28706 Roo.ToolbarButton = Roo.Toolbar.Button;
28709 * @class Roo.Toolbar.SplitButton
28710 * @extends Roo.SplitButton
28711 * A menu button that renders into a toolbar.
28713 * Creates a new SplitButton
28714 * @param {Object} config A standard {@link Roo.SplitButton} config object
28716 Roo.Toolbar.SplitButton = function(config){
28717 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28719 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28720 render : function(td){
28722 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28726 * Removes and destroys this button
28728 destroy : function(){
28729 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28730 this.td.parentNode.removeChild(this.td);
28734 * Shows this button
28737 this.hidden = false;
28738 this.td.style.display = "";
28742 * Hides this button
28745 this.hidden = true;
28746 this.td.style.display = "none";
28750 // backwards compat
28751 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28753 * Ext JS Library 1.1.1
28754 * Copyright(c) 2006-2007, Ext JS, LLC.
28756 * Originally Released Under LGPL - original licence link has changed is not relivant.
28759 * <script type="text/javascript">
28763 * @class Roo.PagingToolbar
28764 * @extends Roo.Toolbar
28765 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28767 * Create a new PagingToolbar
28768 * @param {Object} config The config object
28770 Roo.PagingToolbar = function(el, ds, config)
28772 // old args format still supported... - xtype is prefered..
28773 if (typeof(el) == 'object' && el.xtype) {
28774 // created from xtype...
28776 ds = el.dataSource;
28777 el = config.container;
28780 if (config.items) {
28781 items = config.items;
28785 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28788 this.renderButtons(this.el);
28791 // supprot items array.
28793 Roo.each(items, function(e) {
28794 this.add(Roo.factory(e));
28799 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28801 * @cfg {Roo.data.Store} dataSource
28802 * The underlying data store providing the paged data
28805 * @cfg {String/HTMLElement/Element} container
28806 * container The id or element that will contain the toolbar
28809 * @cfg {Boolean} displayInfo
28810 * True to display the displayMsg (defaults to false)
28813 * @cfg {Number} pageSize
28814 * The number of records to display per page (defaults to 20)
28818 * @cfg {String} displayMsg
28819 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28821 displayMsg : 'Displaying {0} - {1} of {2}',
28823 * @cfg {String} emptyMsg
28824 * The message to display when no records are found (defaults to "No data to display")
28826 emptyMsg : 'No data to display',
28828 * Customizable piece of the default paging text (defaults to "Page")
28831 beforePageText : "Page",
28833 * Customizable piece of the default paging text (defaults to "of %0")
28836 afterPageText : "of {0}",
28838 * Customizable piece of the default paging text (defaults to "First Page")
28841 firstText : "First Page",
28843 * Customizable piece of the default paging text (defaults to "Previous Page")
28846 prevText : "Previous Page",
28848 * Customizable piece of the default paging text (defaults to "Next Page")
28851 nextText : "Next Page",
28853 * Customizable piece of the default paging text (defaults to "Last Page")
28856 lastText : "Last Page",
28858 * Customizable piece of the default paging text (defaults to "Refresh")
28861 refreshText : "Refresh",
28864 renderButtons : function(el){
28865 Roo.PagingToolbar.superclass.render.call(this, el);
28866 this.first = this.addButton({
28867 tooltip: this.firstText,
28868 cls: "x-btn-icon x-grid-page-first",
28870 handler: this.onClick.createDelegate(this, ["first"])
28872 this.prev = this.addButton({
28873 tooltip: this.prevText,
28874 cls: "x-btn-icon x-grid-page-prev",
28876 handler: this.onClick.createDelegate(this, ["prev"])
28878 //this.addSeparator();
28879 this.add(this.beforePageText);
28880 this.field = Roo.get(this.addDom({
28885 cls: "x-grid-page-number"
28887 this.field.on("keydown", this.onPagingKeydown, this);
28888 this.field.on("focus", function(){this.dom.select();});
28889 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28890 this.field.setHeight(18);
28891 //this.addSeparator();
28892 this.next = this.addButton({
28893 tooltip: this.nextText,
28894 cls: "x-btn-icon x-grid-page-next",
28896 handler: this.onClick.createDelegate(this, ["next"])
28898 this.last = this.addButton({
28899 tooltip: this.lastText,
28900 cls: "x-btn-icon x-grid-page-last",
28902 handler: this.onClick.createDelegate(this, ["last"])
28904 //this.addSeparator();
28905 this.loading = this.addButton({
28906 tooltip: this.refreshText,
28907 cls: "x-btn-icon x-grid-loading",
28908 handler: this.onClick.createDelegate(this, ["refresh"])
28911 if(this.displayInfo){
28912 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28917 updateInfo : function(){
28918 if(this.displayEl){
28919 var count = this.ds.getCount();
28920 var msg = count == 0 ?
28924 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28926 this.displayEl.update(msg);
28931 onLoad : function(ds, r, o){
28932 this.cursor = o.params ? o.params.start : 0;
28933 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28935 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28936 this.field.dom.value = ap;
28937 this.first.setDisabled(ap == 1);
28938 this.prev.setDisabled(ap == 1);
28939 this.next.setDisabled(ap == ps);
28940 this.last.setDisabled(ap == ps);
28941 this.loading.enable();
28946 getPageData : function(){
28947 var total = this.ds.getTotalCount();
28950 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28951 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28956 onLoadError : function(){
28957 this.loading.enable();
28961 onPagingKeydown : function(e){
28962 var k = e.getKey();
28963 var d = this.getPageData();
28965 var v = this.field.dom.value, pageNum;
28966 if(!v || isNaN(pageNum = parseInt(v, 10))){
28967 this.field.dom.value = d.activePage;
28970 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28971 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28974 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))
28976 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28977 this.field.dom.value = pageNum;
28978 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28981 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28983 var v = this.field.dom.value, pageNum;
28984 var increment = (e.shiftKey) ? 10 : 1;
28985 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28987 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28988 this.field.dom.value = d.activePage;
28991 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28993 this.field.dom.value = parseInt(v, 10) + increment;
28994 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28995 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29002 beforeLoad : function(){
29004 this.loading.disable();
29009 onClick : function(which){
29013 ds.load({params:{start: 0, limit: this.pageSize}});
29016 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
29019 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
29022 var total = ds.getTotalCount();
29023 var extra = total % this.pageSize;
29024 var lastStart = extra ? (total - extra) : total-this.pageSize;
29025 ds.load({params:{start: lastStart, limit: this.pageSize}});
29028 ds.load({params:{start: this.cursor, limit: this.pageSize}});
29034 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
29035 * @param {Roo.data.Store} store The data store to unbind
29037 unbind : function(ds){
29038 ds.un("beforeload", this.beforeLoad, this);
29039 ds.un("load", this.onLoad, this);
29040 ds.un("loadexception", this.onLoadError, this);
29041 ds.un("remove", this.updateInfo, this);
29042 ds.un("add", this.updateInfo, this);
29043 this.ds = undefined;
29047 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29048 * @param {Roo.data.Store} store The data store to bind
29050 bind : function(ds){
29051 ds.on("beforeload", this.beforeLoad, this);
29052 ds.on("load", this.onLoad, this);
29053 ds.on("loadexception", this.onLoadError, this);
29054 ds.on("remove", this.updateInfo, this);
29055 ds.on("add", this.updateInfo, this);
29060 * Ext JS Library 1.1.1
29061 * Copyright(c) 2006-2007, Ext JS, LLC.
29063 * Originally Released Under LGPL - original licence link has changed is not relivant.
29066 * <script type="text/javascript">
29070 * @class Roo.Resizable
29071 * @extends Roo.util.Observable
29072 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29073 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29074 * 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
29075 * the element will be wrapped for you automatically.</p>
29076 * <p>Here is the list of valid resize handles:</p>
29079 ------ -------------------
29088 'hd' horizontal drag
29091 * <p>Here's an example showing the creation of a typical Resizable:</p>
29093 var resizer = new Roo.Resizable("element-id", {
29101 resizer.on("resize", myHandler);
29103 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29104 * resizer.east.setDisplayed(false);</p>
29105 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29106 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29107 * resize operation's new size (defaults to [0, 0])
29108 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29109 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29110 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29111 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29112 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29113 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29114 * @cfg {Number} width The width of the element in pixels (defaults to null)
29115 * @cfg {Number} height The height of the element in pixels (defaults to null)
29116 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29117 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29118 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29119 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29120 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29121 * in favor of the handles config option (defaults to false)
29122 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29123 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29124 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29125 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29126 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29127 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29128 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29129 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29130 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29131 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29132 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29134 * Create a new resizable component
29135 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29136 * @param {Object} config configuration options
29138 Roo.Resizable = function(el, config)
29140 this.el = Roo.get(el);
29142 if(config && config.wrap){
29143 config.resizeChild = this.el;
29144 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29145 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29146 this.el.setStyle("overflow", "hidden");
29147 this.el.setPositioning(config.resizeChild.getPositioning());
29148 config.resizeChild.clearPositioning();
29149 if(!config.width || !config.height){
29150 var csize = config.resizeChild.getSize();
29151 this.el.setSize(csize.width, csize.height);
29153 if(config.pinned && !config.adjustments){
29154 config.adjustments = "auto";
29158 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29159 this.proxy.unselectable();
29160 this.proxy.enableDisplayMode('block');
29162 Roo.apply(this, config);
29165 this.disableTrackOver = true;
29166 this.el.addClass("x-resizable-pinned");
29168 // if the element isn't positioned, make it relative
29169 var position = this.el.getStyle("position");
29170 if(position != "absolute" && position != "fixed"){
29171 this.el.setStyle("position", "relative");
29173 if(!this.handles){ // no handles passed, must be legacy style
29174 this.handles = 's,e,se';
29175 if(this.multiDirectional){
29176 this.handles += ',n,w';
29179 if(this.handles == "all"){
29180 this.handles = "n s e w ne nw se sw";
29182 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29183 var ps = Roo.Resizable.positions;
29184 for(var i = 0, len = hs.length; i < len; i++){
29185 if(hs[i] && ps[hs[i]]){
29186 var pos = ps[hs[i]];
29187 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29191 this.corner = this.southeast;
29193 // updateBox = the box can move..
29194 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29195 this.updateBox = true;
29198 this.activeHandle = null;
29200 if(this.resizeChild){
29201 if(typeof this.resizeChild == "boolean"){
29202 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29204 this.resizeChild = Roo.get(this.resizeChild, true);
29208 if(this.adjustments == "auto"){
29209 var rc = this.resizeChild;
29210 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29211 if(rc && (hw || hn)){
29212 rc.position("relative");
29213 rc.setLeft(hw ? hw.el.getWidth() : 0);
29214 rc.setTop(hn ? hn.el.getHeight() : 0);
29216 this.adjustments = [
29217 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29218 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29222 if(this.draggable){
29223 this.dd = this.dynamic ?
29224 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29225 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29231 * @event beforeresize
29232 * Fired before resize is allowed. Set enabled to false to cancel resize.
29233 * @param {Roo.Resizable} this
29234 * @param {Roo.EventObject} e The mousedown event
29236 "beforeresize" : true,
29239 * Fired a resizing.
29240 * @param {Roo.Resizable} this
29241 * @param {Number} x The new x position
29242 * @param {Number} y The new y position
29243 * @param {Number} w The new w width
29244 * @param {Number} h The new h hight
29245 * @param {Roo.EventObject} e The mouseup event
29250 * Fired after a resize.
29251 * @param {Roo.Resizable} this
29252 * @param {Number} width The new width
29253 * @param {Number} height The new height
29254 * @param {Roo.EventObject} e The mouseup event
29259 if(this.width !== null && this.height !== null){
29260 this.resizeTo(this.width, this.height);
29262 this.updateChildSize();
29265 this.el.dom.style.zoom = 1;
29267 Roo.Resizable.superclass.constructor.call(this);
29270 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29271 resizeChild : false,
29272 adjustments : [0, 0],
29282 multiDirectional : false,
29283 disableTrackOver : false,
29284 easing : 'easeOutStrong',
29285 widthIncrement : 0,
29286 heightIncrement : 0,
29290 preserveRatio : false,
29291 transparent: false,
29297 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29299 constrainTo: undefined,
29301 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29303 resizeRegion: undefined,
29307 * Perform a manual resize
29308 * @param {Number} width
29309 * @param {Number} height
29311 resizeTo : function(width, height){
29312 this.el.setSize(width, height);
29313 this.updateChildSize();
29314 this.fireEvent("resize", this, width, height, null);
29318 startSizing : function(e, handle){
29319 this.fireEvent("beforeresize", this, e);
29320 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29323 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29324 this.overlay.unselectable();
29325 this.overlay.enableDisplayMode("block");
29326 this.overlay.on("mousemove", this.onMouseMove, this);
29327 this.overlay.on("mouseup", this.onMouseUp, this);
29329 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29331 this.resizing = true;
29332 this.startBox = this.el.getBox();
29333 this.startPoint = e.getXY();
29334 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29335 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29337 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29338 this.overlay.show();
29340 if(this.constrainTo) {
29341 var ct = Roo.get(this.constrainTo);
29342 this.resizeRegion = ct.getRegion().adjust(
29343 ct.getFrameWidth('t'),
29344 ct.getFrameWidth('l'),
29345 -ct.getFrameWidth('b'),
29346 -ct.getFrameWidth('r')
29350 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29352 this.proxy.setBox(this.startBox);
29354 this.proxy.setStyle('visibility', 'visible');
29360 onMouseDown : function(handle, e){
29363 this.activeHandle = handle;
29364 this.startSizing(e, handle);
29369 onMouseUp : function(e){
29370 var size = this.resizeElement();
29371 this.resizing = false;
29373 this.overlay.hide();
29375 this.fireEvent("resize", this, size.width, size.height, e);
29379 updateChildSize : function(){
29381 if(this.resizeChild){
29383 var child = this.resizeChild;
29384 var adj = this.adjustments;
29385 if(el.dom.offsetWidth){
29386 var b = el.getSize(true);
29387 child.setSize(b.width+adj[0], b.height+adj[1]);
29389 // Second call here for IE
29390 // The first call enables instant resizing and
29391 // the second call corrects scroll bars if they
29394 setTimeout(function(){
29395 if(el.dom.offsetWidth){
29396 var b = el.getSize(true);
29397 child.setSize(b.width+adj[0], b.height+adj[1]);
29405 snap : function(value, inc, min){
29406 if(!inc || !value) return value;
29407 var newValue = value;
29408 var m = value % inc;
29411 newValue = value + (inc-m);
29413 newValue = value - m;
29416 return Math.max(min, newValue);
29420 resizeElement : function(){
29421 var box = this.proxy.getBox();
29422 if(this.updateBox){
29423 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29425 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29427 this.updateChildSize();
29435 constrain : function(v, diff, m, mx){
29438 }else if(v - diff > mx){
29445 onMouseMove : function(e){
29448 try{// try catch so if something goes wrong the user doesn't get hung
29450 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29454 //var curXY = this.startPoint;
29455 var curSize = this.curSize || this.startBox;
29456 var x = this.startBox.x, y = this.startBox.y;
29457 var ox = x, oy = y;
29458 var w = curSize.width, h = curSize.height;
29459 var ow = w, oh = h;
29460 var mw = this.minWidth, mh = this.minHeight;
29461 var mxw = this.maxWidth, mxh = this.maxHeight;
29462 var wi = this.widthIncrement;
29463 var hi = this.heightIncrement;
29465 var eventXY = e.getXY();
29466 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29467 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29469 var pos = this.activeHandle.position;
29474 w = Math.min(Math.max(mw, w), mxw);
29479 h = Math.min(Math.max(mh, h), mxh);
29484 w = Math.min(Math.max(mw, w), mxw);
29485 h = Math.min(Math.max(mh, h), mxh);
29488 diffY = this.constrain(h, diffY, mh, mxh);
29495 var adiffX = Math.abs(diffX);
29496 var sub = (adiffX % wi); // how much
29497 if (sub > (wi/2)) { // far enough to snap
29498 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29500 // remove difference..
29501 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29505 x = Math.max(this.minX, x);
29508 diffX = this.constrain(w, diffX, mw, mxw);
29514 w = Math.min(Math.max(mw, w), mxw);
29515 diffY = this.constrain(h, diffY, mh, mxh);
29520 diffX = this.constrain(w, diffX, mw, mxw);
29521 diffY = this.constrain(h, diffY, mh, mxh);
29528 diffX = this.constrain(w, diffX, mw, mxw);
29530 h = Math.min(Math.max(mh, h), mxh);
29536 var sw = this.snap(w, wi, mw);
29537 var sh = this.snap(h, hi, mh);
29538 if(sw != w || sh != h){
29561 if(this.preserveRatio){
29566 h = Math.min(Math.max(mh, h), mxh);
29571 w = Math.min(Math.max(mw, w), mxw);
29576 w = Math.min(Math.max(mw, w), mxw);
29582 w = Math.min(Math.max(mw, w), mxw);
29588 h = Math.min(Math.max(mh, h), mxh);
29596 h = Math.min(Math.max(mh, h), mxh);
29606 h = Math.min(Math.max(mh, h), mxh);
29614 if (pos == 'hdrag') {
29617 this.proxy.setBounds(x, y, w, h);
29619 this.resizeElement();
29623 this.fireEvent("resizing", this, x, y, w, h, e);
29627 handleOver : function(){
29629 this.el.addClass("x-resizable-over");
29634 handleOut : function(){
29635 if(!this.resizing){
29636 this.el.removeClass("x-resizable-over");
29641 * Returns the element this component is bound to.
29642 * @return {Roo.Element}
29644 getEl : function(){
29649 * Returns the resizeChild element (or null).
29650 * @return {Roo.Element}
29652 getResizeChild : function(){
29653 return this.resizeChild;
29655 groupHandler : function()
29660 * Destroys this resizable. If the element was wrapped and
29661 * removeEl is not true then the element remains.
29662 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29664 destroy : function(removeEl){
29665 this.proxy.remove();
29667 this.overlay.removeAllListeners();
29668 this.overlay.remove();
29670 var ps = Roo.Resizable.positions;
29672 if(typeof ps[k] != "function" && this[ps[k]]){
29673 var h = this[ps[k]];
29674 h.el.removeAllListeners();
29679 this.el.update("");
29686 // hash to map config positions to true positions
29687 Roo.Resizable.positions = {
29688 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29693 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29695 // only initialize the template if resizable is used
29696 var tpl = Roo.DomHelper.createTemplate(
29697 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29700 Roo.Resizable.Handle.prototype.tpl = tpl;
29702 this.position = pos;
29704 // show north drag fro topdra
29705 var handlepos = pos == 'hdrag' ? 'north' : pos;
29707 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29708 if (pos == 'hdrag') {
29709 this.el.setStyle('cursor', 'pointer');
29711 this.el.unselectable();
29713 this.el.setOpacity(0);
29715 this.el.on("mousedown", this.onMouseDown, this);
29716 if(!disableTrackOver){
29717 this.el.on("mouseover", this.onMouseOver, this);
29718 this.el.on("mouseout", this.onMouseOut, this);
29723 Roo.Resizable.Handle.prototype = {
29724 afterResize : function(rz){
29729 onMouseDown : function(e){
29730 this.rz.onMouseDown(this, e);
29733 onMouseOver : function(e){
29734 this.rz.handleOver(this, e);
29737 onMouseOut : function(e){
29738 this.rz.handleOut(this, e);
29742 * Ext JS Library 1.1.1
29743 * Copyright(c) 2006-2007, Ext JS, LLC.
29745 * Originally Released Under LGPL - original licence link has changed is not relivant.
29748 * <script type="text/javascript">
29752 * @class Roo.Editor
29753 * @extends Roo.Component
29754 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29756 * Create a new Editor
29757 * @param {Roo.form.Field} field The Field object (or descendant)
29758 * @param {Object} config The config object
29760 Roo.Editor = function(field, config){
29761 Roo.Editor.superclass.constructor.call(this, config);
29762 this.field = field;
29765 * @event beforestartedit
29766 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29767 * false from the handler of this event.
29768 * @param {Editor} this
29769 * @param {Roo.Element} boundEl The underlying element bound to this editor
29770 * @param {Mixed} value The field value being set
29772 "beforestartedit" : true,
29775 * Fires when this editor is displayed
29776 * @param {Roo.Element} boundEl The underlying element bound to this editor
29777 * @param {Mixed} value The starting field value
29779 "startedit" : true,
29781 * @event beforecomplete
29782 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29783 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29784 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29785 * event will not fire since no edit actually occurred.
29786 * @param {Editor} this
29787 * @param {Mixed} value The current field value
29788 * @param {Mixed} startValue The original field value
29790 "beforecomplete" : true,
29793 * Fires after editing is complete and any changed value has been written to the underlying field.
29794 * @param {Editor} this
29795 * @param {Mixed} value The current field value
29796 * @param {Mixed} startValue The original field value
29800 * @event specialkey
29801 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29802 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29803 * @param {Roo.form.Field} this
29804 * @param {Roo.EventObject} e The event object
29806 "specialkey" : true
29810 Roo.extend(Roo.Editor, Roo.Component, {
29812 * @cfg {Boolean/String} autosize
29813 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29814 * or "height" to adopt the height only (defaults to false)
29817 * @cfg {Boolean} revertInvalid
29818 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29819 * validation fails (defaults to true)
29822 * @cfg {Boolean} ignoreNoChange
29823 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29824 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29825 * will never be ignored.
29828 * @cfg {Boolean} hideEl
29829 * False to keep the bound element visible while the editor is displayed (defaults to true)
29832 * @cfg {Mixed} value
29833 * The data value of the underlying field (defaults to "")
29837 * @cfg {String} alignment
29838 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29842 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29843 * for bottom-right shadow (defaults to "frame")
29847 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29851 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29853 completeOnEnter : false,
29855 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29857 cancelOnEsc : false,
29859 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29864 onRender : function(ct, position){
29865 this.el = new Roo.Layer({
29866 shadow: this.shadow,
29872 constrain: this.constrain
29874 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29875 if(this.field.msgTarget != 'title'){
29876 this.field.msgTarget = 'qtip';
29878 this.field.render(this.el);
29880 this.field.el.dom.setAttribute('autocomplete', 'off');
29882 this.field.on("specialkey", this.onSpecialKey, this);
29883 if(this.swallowKeys){
29884 this.field.el.swallowEvent(['keydown','keypress']);
29887 this.field.on("blur", this.onBlur, this);
29888 if(this.field.grow){
29889 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29893 onSpecialKey : function(field, e)
29895 //Roo.log('editor onSpecialKey');
29896 if(this.completeOnEnter && e.getKey() == e.ENTER){
29898 this.completeEdit();
29901 // do not fire special key otherwise it might hide close the editor...
29902 if(e.getKey() == e.ENTER){
29905 if(this.cancelOnEsc && e.getKey() == e.ESC){
29909 this.fireEvent('specialkey', field, e);
29914 * Starts the editing process and shows the editor.
29915 * @param {String/HTMLElement/Element} el The element to edit
29916 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29917 * to the innerHTML of el.
29919 startEdit : function(el, value){
29921 this.completeEdit();
29923 this.boundEl = Roo.get(el);
29924 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29925 if(!this.rendered){
29926 this.render(this.parentEl || document.body);
29928 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29931 this.startValue = v;
29932 this.field.setValue(v);
29934 var sz = this.boundEl.getSize();
29935 switch(this.autoSize){
29937 this.setSize(sz.width, "");
29940 this.setSize("", sz.height);
29943 this.setSize(sz.width, sz.height);
29946 this.el.alignTo(this.boundEl, this.alignment);
29947 this.editing = true;
29949 Roo.QuickTips.disable();
29955 * Sets the height and width of this editor.
29956 * @param {Number} width The new width
29957 * @param {Number} height The new height
29959 setSize : function(w, h){
29960 this.field.setSize(w, h);
29967 * Realigns the editor to the bound field based on the current alignment config value.
29969 realign : function(){
29970 this.el.alignTo(this.boundEl, this.alignment);
29974 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29975 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29977 completeEdit : function(remainVisible){
29981 var v = this.getValue();
29982 if(this.revertInvalid !== false && !this.field.isValid()){
29983 v = this.startValue;
29984 this.cancelEdit(true);
29986 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29987 this.editing = false;
29991 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29992 this.editing = false;
29993 if(this.updateEl && this.boundEl){
29994 this.boundEl.update(v);
29996 if(remainVisible !== true){
29999 this.fireEvent("complete", this, v, this.startValue);
30004 onShow : function(){
30006 if(this.hideEl !== false){
30007 this.boundEl.hide();
30010 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
30011 this.fixIEFocus = true;
30012 this.deferredFocus.defer(50, this);
30014 this.field.focus();
30016 this.fireEvent("startedit", this.boundEl, this.startValue);
30019 deferredFocus : function(){
30021 this.field.focus();
30026 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
30027 * reverted to the original starting value.
30028 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
30029 * cancel (defaults to false)
30031 cancelEdit : function(remainVisible){
30033 this.setValue(this.startValue);
30034 if(remainVisible !== true){
30041 onBlur : function(){
30042 if(this.allowBlur !== true && this.editing){
30043 this.completeEdit();
30048 onHide : function(){
30050 this.completeEdit();
30054 if(this.field.collapse){
30055 this.field.collapse();
30058 if(this.hideEl !== false){
30059 this.boundEl.show();
30062 Roo.QuickTips.enable();
30067 * Sets the data value of the editor
30068 * @param {Mixed} value Any valid value supported by the underlying field
30070 setValue : function(v){
30071 this.field.setValue(v);
30075 * Gets the data value of the editor
30076 * @return {Mixed} The data value
30078 getValue : function(){
30079 return this.field.getValue();
30083 * Ext JS Library 1.1.1
30084 * Copyright(c) 2006-2007, Ext JS, LLC.
30086 * Originally Released Under LGPL - original licence link has changed is not relivant.
30089 * <script type="text/javascript">
30093 * @class Roo.BasicDialog
30094 * @extends Roo.util.Observable
30095 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30097 var dlg = new Roo.BasicDialog("my-dlg", {
30106 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30107 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30108 dlg.addButton('Cancel', dlg.hide, dlg);
30111 <b>A Dialog should always be a direct child of the body element.</b>
30112 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30113 * @cfg {String} title Default text to display in the title bar (defaults to null)
30114 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30115 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30116 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30117 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30118 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30119 * (defaults to null with no animation)
30120 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30121 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30122 * property for valid values (defaults to 'all')
30123 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30124 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30125 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30126 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30127 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30128 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30129 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30130 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30131 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30132 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30133 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30134 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30135 * draggable = true (defaults to false)
30136 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30137 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30138 * shadow (defaults to false)
30139 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30140 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30141 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30142 * @cfg {Array} buttons Array of buttons
30143 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30145 * Create a new BasicDialog.
30146 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30147 * @param {Object} config Configuration options
30149 Roo.BasicDialog = function(el, config){
30150 this.el = Roo.get(el);
30151 var dh = Roo.DomHelper;
30152 if(!this.el && config && config.autoCreate){
30153 if(typeof config.autoCreate == "object"){
30154 if(!config.autoCreate.id){
30155 config.autoCreate.id = el;
30157 this.el = dh.append(document.body,
30158 config.autoCreate, true);
30160 this.el = dh.append(document.body,
30161 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30165 el.setDisplayed(true);
30166 el.hide = this.hideAction;
30168 el.addClass("x-dlg");
30170 Roo.apply(this, config);
30172 this.proxy = el.createProxy("x-dlg-proxy");
30173 this.proxy.hide = this.hideAction;
30174 this.proxy.setOpacity(.5);
30178 el.setWidth(config.width);
30181 el.setHeight(config.height);
30183 this.size = el.getSize();
30184 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30185 this.xy = [config.x,config.y];
30187 this.xy = el.getCenterXY(true);
30189 /** The header element @type Roo.Element */
30190 this.header = el.child("> .x-dlg-hd");
30191 /** The body element @type Roo.Element */
30192 this.body = el.child("> .x-dlg-bd");
30193 /** The footer element @type Roo.Element */
30194 this.footer = el.child("> .x-dlg-ft");
30197 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30200 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30203 this.header.unselectable();
30205 this.header.update(this.title);
30207 // this element allows the dialog to be focused for keyboard event
30208 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30209 this.focusEl.swallowEvent("click", true);
30211 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30213 // wrap the body and footer for special rendering
30214 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30216 this.bwrap.dom.appendChild(this.footer.dom);
30219 this.bg = this.el.createChild({
30220 tag: "div", cls:"x-dlg-bg",
30221 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30223 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30226 if(this.autoScroll !== false && !this.autoTabs){
30227 this.body.setStyle("overflow", "auto");
30230 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30232 if(this.closable !== false){
30233 this.el.addClass("x-dlg-closable");
30234 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30235 this.close.on("click", this.closeClick, this);
30236 this.close.addClassOnOver("x-dlg-close-over");
30238 if(this.collapsible !== false){
30239 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30240 this.collapseBtn.on("click", this.collapseClick, this);
30241 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30242 this.header.on("dblclick", this.collapseClick, this);
30244 if(this.resizable !== false){
30245 this.el.addClass("x-dlg-resizable");
30246 this.resizer = new Roo.Resizable(el, {
30247 minWidth: this.minWidth || 80,
30248 minHeight:this.minHeight || 80,
30249 handles: this.resizeHandles || "all",
30252 this.resizer.on("beforeresize", this.beforeResize, this);
30253 this.resizer.on("resize", this.onResize, this);
30255 if(this.draggable !== false){
30256 el.addClass("x-dlg-draggable");
30257 if (!this.proxyDrag) {
30258 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30261 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30263 dd.setHandleElId(this.header.id);
30264 dd.endDrag = this.endMove.createDelegate(this);
30265 dd.startDrag = this.startMove.createDelegate(this);
30266 dd.onDrag = this.onDrag.createDelegate(this);
30271 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30272 this.mask.enableDisplayMode("block");
30274 this.el.addClass("x-dlg-modal");
30277 this.shadow = new Roo.Shadow({
30278 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30279 offset : this.shadowOffset
30282 this.shadowOffset = 0;
30284 if(Roo.useShims && this.shim !== false){
30285 this.shim = this.el.createShim();
30286 this.shim.hide = this.hideAction;
30294 if (this.buttons) {
30295 var bts= this.buttons;
30297 Roo.each(bts, function(b) {
30306 * Fires when a key is pressed
30307 * @param {Roo.BasicDialog} this
30308 * @param {Roo.EventObject} e
30313 * Fires when this dialog is moved by the user.
30314 * @param {Roo.BasicDialog} this
30315 * @param {Number} x The new page X
30316 * @param {Number} y The new page Y
30321 * Fires when this dialog is resized by the user.
30322 * @param {Roo.BasicDialog} this
30323 * @param {Number} width The new width
30324 * @param {Number} height The new height
30328 * @event beforehide
30329 * Fires before this dialog is hidden.
30330 * @param {Roo.BasicDialog} this
30332 "beforehide" : true,
30335 * Fires when this dialog is hidden.
30336 * @param {Roo.BasicDialog} this
30340 * @event beforeshow
30341 * Fires before this dialog is shown.
30342 * @param {Roo.BasicDialog} this
30344 "beforeshow" : true,
30347 * Fires when this dialog is shown.
30348 * @param {Roo.BasicDialog} this
30352 el.on("keydown", this.onKeyDown, this);
30353 el.on("mousedown", this.toFront, this);
30354 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30356 Roo.DialogManager.register(this);
30357 Roo.BasicDialog.superclass.constructor.call(this);
30360 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30361 shadowOffset: Roo.isIE ? 6 : 5,
30364 minButtonWidth: 75,
30365 defaultButton: null,
30366 buttonAlign: "right",
30371 * Sets the dialog title text
30372 * @param {String} text The title text to display
30373 * @return {Roo.BasicDialog} this
30375 setTitle : function(text){
30376 this.header.update(text);
30381 closeClick : function(){
30386 collapseClick : function(){
30387 this[this.collapsed ? "expand" : "collapse"]();
30391 * Collapses the dialog to its minimized state (only the title bar is visible).
30392 * Equivalent to the user clicking the collapse dialog button.
30394 collapse : function(){
30395 if(!this.collapsed){
30396 this.collapsed = true;
30397 this.el.addClass("x-dlg-collapsed");
30398 this.restoreHeight = this.el.getHeight();
30399 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30404 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30405 * clicking the expand dialog button.
30407 expand : function(){
30408 if(this.collapsed){
30409 this.collapsed = false;
30410 this.el.removeClass("x-dlg-collapsed");
30411 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30416 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30417 * @return {Roo.TabPanel} The tabs component
30419 initTabs : function(){
30420 var tabs = this.getTabs();
30421 while(tabs.getTab(0)){
30424 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30426 tabs.addTab(Roo.id(dom), dom.title);
30434 beforeResize : function(){
30435 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30439 onResize : function(){
30440 this.refreshSize();
30441 this.syncBodyHeight();
30442 this.adjustAssets();
30444 this.fireEvent("resize", this, this.size.width, this.size.height);
30448 onKeyDown : function(e){
30449 if(this.isVisible()){
30450 this.fireEvent("keydown", this, e);
30455 * Resizes the dialog.
30456 * @param {Number} width
30457 * @param {Number} height
30458 * @return {Roo.BasicDialog} this
30460 resizeTo : function(width, height){
30461 this.el.setSize(width, height);
30462 this.size = {width: width, height: height};
30463 this.syncBodyHeight();
30464 if(this.fixedcenter){
30467 if(this.isVisible()){
30468 this.constrainXY();
30469 this.adjustAssets();
30471 this.fireEvent("resize", this, width, height);
30477 * Resizes the dialog to fit the specified content size.
30478 * @param {Number} width
30479 * @param {Number} height
30480 * @return {Roo.BasicDialog} this
30482 setContentSize : function(w, h){
30483 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30484 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30485 //if(!this.el.isBorderBox()){
30486 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30487 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30490 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30491 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30493 this.resizeTo(w, h);
30498 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30499 * executed in response to a particular key being pressed while the dialog is active.
30500 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30501 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30502 * @param {Function} fn The function to call
30503 * @param {Object} scope (optional) The scope of the function
30504 * @return {Roo.BasicDialog} this
30506 addKeyListener : function(key, fn, scope){
30507 var keyCode, shift, ctrl, alt;
30508 if(typeof key == "object" && !(key instanceof Array)){
30509 keyCode = key["key"];
30510 shift = key["shift"];
30511 ctrl = key["ctrl"];
30516 var handler = function(dlg, e){
30517 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30518 var k = e.getKey();
30519 if(keyCode instanceof Array){
30520 for(var i = 0, len = keyCode.length; i < len; i++){
30521 if(keyCode[i] == k){
30522 fn.call(scope || window, dlg, k, e);
30528 fn.call(scope || window, dlg, k, e);
30533 this.on("keydown", handler);
30538 * Returns the TabPanel component (creates it if it doesn't exist).
30539 * Note: If you wish to simply check for the existence of tabs without creating them,
30540 * check for a null 'tabs' property.
30541 * @return {Roo.TabPanel} The tabs component
30543 getTabs : function(){
30545 this.el.addClass("x-dlg-auto-tabs");
30546 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30547 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30553 * Adds a button to the footer section of the dialog.
30554 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30555 * object or a valid Roo.DomHelper element config
30556 * @param {Function} handler The function called when the button is clicked
30557 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30558 * @return {Roo.Button} The new button
30560 addButton : function(config, handler, scope){
30561 var dh = Roo.DomHelper;
30563 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30565 if(!this.btnContainer){
30566 var tb = this.footer.createChild({
30568 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30569 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30571 this.btnContainer = tb.firstChild.firstChild.firstChild;
30576 minWidth: this.minButtonWidth,
30579 if(typeof config == "string"){
30580 bconfig.text = config;
30583 bconfig.dhconfig = config;
30585 Roo.apply(bconfig, config);
30589 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30590 bconfig.position = Math.max(0, bconfig.position);
30591 fc = this.btnContainer.childNodes[bconfig.position];
30594 var btn = new Roo.Button(
30596 this.btnContainer.insertBefore(document.createElement("td"),fc)
30597 : this.btnContainer.appendChild(document.createElement("td")),
30598 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30601 this.syncBodyHeight();
30604 * Array of all the buttons that have been added to this dialog via addButton
30609 this.buttons.push(btn);
30614 * Sets the default button to be focused when the dialog is displayed.
30615 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30616 * @return {Roo.BasicDialog} this
30618 setDefaultButton : function(btn){
30619 this.defaultButton = btn;
30624 getHeaderFooterHeight : function(safe){
30627 height += this.header.getHeight();
30630 var fm = this.footer.getMargins();
30631 height += (this.footer.getHeight()+fm.top+fm.bottom);
30633 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30634 height += this.centerBg.getPadding("tb");
30639 syncBodyHeight : function()
30641 var bd = this.body, // the text
30642 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30644 var height = this.size.height - this.getHeaderFooterHeight(false);
30645 bd.setHeight(height-bd.getMargins("tb"));
30646 var hh = this.header.getHeight();
30647 var h = this.size.height-hh;
30650 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30651 bw.setHeight(h-cb.getPadding("tb"));
30653 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30654 bd.setWidth(bw.getWidth(true));
30656 this.tabs.syncHeight();
30658 this.tabs.el.repaint();
30664 * Restores the previous state of the dialog if Roo.state is configured.
30665 * @return {Roo.BasicDialog} this
30667 restoreState : function(){
30668 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30669 if(box && box.width){
30670 this.xy = [box.x, box.y];
30671 this.resizeTo(box.width, box.height);
30677 beforeShow : function(){
30679 if(this.fixedcenter){
30680 this.xy = this.el.getCenterXY(true);
30683 Roo.get(document.body).addClass("x-body-masked");
30684 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30687 this.constrainXY();
30691 animShow : function(){
30692 var b = Roo.get(this.animateTarget).getBox();
30693 this.proxy.setSize(b.width, b.height);
30694 this.proxy.setLocation(b.x, b.y);
30696 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30697 true, .35, this.showEl.createDelegate(this));
30701 * Shows the dialog.
30702 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30703 * @return {Roo.BasicDialog} this
30705 show : function(animateTarget){
30706 if (this.fireEvent("beforeshow", this) === false){
30709 if(this.syncHeightBeforeShow){
30710 this.syncBodyHeight();
30711 }else if(this.firstShow){
30712 this.firstShow = false;
30713 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30715 this.animateTarget = animateTarget || this.animateTarget;
30716 if(!this.el.isVisible()){
30718 if(this.animateTarget && Roo.get(this.animateTarget)){
30728 showEl : function(){
30730 this.el.setXY(this.xy);
30732 this.adjustAssets(true);
30735 // IE peekaboo bug - fix found by Dave Fenwick
30739 this.fireEvent("show", this);
30743 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30744 * dialog itself will receive focus.
30746 focus : function(){
30747 if(this.defaultButton){
30748 this.defaultButton.focus();
30750 this.focusEl.focus();
30755 constrainXY : function(){
30756 if(this.constraintoviewport !== false){
30757 if(!this.viewSize){
30758 if(this.container){
30759 var s = this.container.getSize();
30760 this.viewSize = [s.width, s.height];
30762 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30765 var s = Roo.get(this.container||document).getScroll();
30767 var x = this.xy[0], y = this.xy[1];
30768 var w = this.size.width, h = this.size.height;
30769 var vw = this.viewSize[0], vh = this.viewSize[1];
30770 // only move it if it needs it
30772 // first validate right/bottom
30773 if(x + w > vw+s.left){
30777 if(y + h > vh+s.top){
30781 // then make sure top/left isn't negative
30793 if(this.isVisible()){
30794 this.el.setLocation(x, y);
30795 this.adjustAssets();
30802 onDrag : function(){
30803 if(!this.proxyDrag){
30804 this.xy = this.el.getXY();
30805 this.adjustAssets();
30810 adjustAssets : function(doShow){
30811 var x = this.xy[0], y = this.xy[1];
30812 var w = this.size.width, h = this.size.height;
30813 if(doShow === true){
30815 this.shadow.show(this.el);
30821 if(this.shadow && this.shadow.isVisible()){
30822 this.shadow.show(this.el);
30824 if(this.shim && this.shim.isVisible()){
30825 this.shim.setBounds(x, y, w, h);
30830 adjustViewport : function(w, h){
30832 w = Roo.lib.Dom.getViewWidth();
30833 h = Roo.lib.Dom.getViewHeight();
30836 this.viewSize = [w, h];
30837 if(this.modal && this.mask.isVisible()){
30838 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30839 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30841 if(this.isVisible()){
30842 this.constrainXY();
30847 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30848 * shadow, proxy, mask, etc.) Also removes all event listeners.
30849 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30851 destroy : function(removeEl){
30852 if(this.isVisible()){
30853 this.animateTarget = null;
30856 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30858 this.tabs.destroy(removeEl);
30871 for(var i = 0, len = this.buttons.length; i < len; i++){
30872 this.buttons[i].destroy();
30875 this.el.removeAllListeners();
30876 if(removeEl === true){
30877 this.el.update("");
30880 Roo.DialogManager.unregister(this);
30884 startMove : function(){
30885 if(this.proxyDrag){
30888 if(this.constraintoviewport !== false){
30889 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30894 endMove : function(){
30895 if(!this.proxyDrag){
30896 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30898 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30901 this.refreshSize();
30902 this.adjustAssets();
30904 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30908 * Brings this dialog to the front of any other visible dialogs
30909 * @return {Roo.BasicDialog} this
30911 toFront : function(){
30912 Roo.DialogManager.bringToFront(this);
30917 * Sends this dialog to the back (under) of any other visible dialogs
30918 * @return {Roo.BasicDialog} this
30920 toBack : function(){
30921 Roo.DialogManager.sendToBack(this);
30926 * Centers this dialog in the viewport
30927 * @return {Roo.BasicDialog} this
30929 center : function(){
30930 var xy = this.el.getCenterXY(true);
30931 this.moveTo(xy[0], xy[1]);
30936 * Moves the dialog's top-left corner to the specified point
30937 * @param {Number} x
30938 * @param {Number} y
30939 * @return {Roo.BasicDialog} this
30941 moveTo : function(x, y){
30943 if(this.isVisible()){
30944 this.el.setXY(this.xy);
30945 this.adjustAssets();
30951 * Aligns the dialog to the specified element
30952 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30953 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30954 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30955 * @return {Roo.BasicDialog} this
30957 alignTo : function(element, position, offsets){
30958 this.xy = this.el.getAlignToXY(element, position, offsets);
30959 if(this.isVisible()){
30960 this.el.setXY(this.xy);
30961 this.adjustAssets();
30967 * Anchors an element to another element and realigns it when the window is resized.
30968 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30969 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30970 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30971 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30972 * is a number, it is used as the buffer delay (defaults to 50ms).
30973 * @return {Roo.BasicDialog} this
30975 anchorTo : function(el, alignment, offsets, monitorScroll){
30976 var action = function(){
30977 this.alignTo(el, alignment, offsets);
30979 Roo.EventManager.onWindowResize(action, this);
30980 var tm = typeof monitorScroll;
30981 if(tm != 'undefined'){
30982 Roo.EventManager.on(window, 'scroll', action, this,
30983 {buffer: tm == 'number' ? monitorScroll : 50});
30990 * Returns true if the dialog is visible
30991 * @return {Boolean}
30993 isVisible : function(){
30994 return this.el.isVisible();
30998 animHide : function(callback){
30999 var b = Roo.get(this.animateTarget).getBox();
31001 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
31003 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
31004 this.hideEl.createDelegate(this, [callback]));
31008 * Hides the dialog.
31009 * @param {Function} callback (optional) Function to call when the dialog is hidden
31010 * @return {Roo.BasicDialog} this
31012 hide : function(callback){
31013 if (this.fireEvent("beforehide", this) === false){
31017 this.shadow.hide();
31022 // sometimes animateTarget seems to get set.. causing problems...
31023 // this just double checks..
31024 if(this.animateTarget && Roo.get(this.animateTarget)) {
31025 this.animHide(callback);
31028 this.hideEl(callback);
31034 hideEl : function(callback){
31038 Roo.get(document.body).removeClass("x-body-masked");
31040 this.fireEvent("hide", this);
31041 if(typeof callback == "function"){
31047 hideAction : function(){
31048 this.setLeft("-10000px");
31049 this.setTop("-10000px");
31050 this.setStyle("visibility", "hidden");
31054 refreshSize : function(){
31055 this.size = this.el.getSize();
31056 this.xy = this.el.getXY();
31057 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31061 // z-index is managed by the DialogManager and may be overwritten at any time
31062 setZIndex : function(index){
31064 this.mask.setStyle("z-index", index);
31067 this.shim.setStyle("z-index", ++index);
31070 this.shadow.setZIndex(++index);
31072 this.el.setStyle("z-index", ++index);
31074 this.proxy.setStyle("z-index", ++index);
31077 this.resizer.proxy.setStyle("z-index", ++index);
31080 this.lastZIndex = index;
31084 * Returns the element for this dialog
31085 * @return {Roo.Element} The underlying dialog Element
31087 getEl : function(){
31093 * @class Roo.DialogManager
31094 * Provides global access to BasicDialogs that have been created and
31095 * support for z-indexing (layering) multiple open dialogs.
31097 Roo.DialogManager = function(){
31099 var accessList = [];
31103 var sortDialogs = function(d1, d2){
31104 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31108 var orderDialogs = function(){
31109 accessList.sort(sortDialogs);
31110 var seed = Roo.DialogManager.zseed;
31111 for(var i = 0, len = accessList.length; i < len; i++){
31112 var dlg = accessList[i];
31114 dlg.setZIndex(seed + (i*10));
31121 * The starting z-index for BasicDialogs (defaults to 9000)
31122 * @type Number The z-index value
31127 register : function(dlg){
31128 list[dlg.id] = dlg;
31129 accessList.push(dlg);
31133 unregister : function(dlg){
31134 delete list[dlg.id];
31137 if(!accessList.indexOf){
31138 for( i = 0, len = accessList.length; i < len; i++){
31139 if(accessList[i] == dlg){
31140 accessList.splice(i, 1);
31145 i = accessList.indexOf(dlg);
31147 accessList.splice(i, 1);
31153 * Gets a registered dialog by id
31154 * @param {String/Object} id The id of the dialog or a dialog
31155 * @return {Roo.BasicDialog} this
31157 get : function(id){
31158 return typeof id == "object" ? id : list[id];
31162 * Brings the specified dialog to the front
31163 * @param {String/Object} dlg The id of the dialog or a dialog
31164 * @return {Roo.BasicDialog} this
31166 bringToFront : function(dlg){
31167 dlg = this.get(dlg);
31170 dlg._lastAccess = new Date().getTime();
31177 * Sends the specified dialog to the back
31178 * @param {String/Object} dlg The id of the dialog or a dialog
31179 * @return {Roo.BasicDialog} this
31181 sendToBack : function(dlg){
31182 dlg = this.get(dlg);
31183 dlg._lastAccess = -(new Date().getTime());
31189 * Hides all dialogs
31191 hideAll : function(){
31192 for(var id in list){
31193 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31202 * @class Roo.LayoutDialog
31203 * @extends Roo.BasicDialog
31204 * Dialog which provides adjustments for working with a layout in a Dialog.
31205 * Add your necessary layout config options to the dialog's config.<br>
31206 * Example usage (including a nested layout):
31209 dialog = new Roo.LayoutDialog("download-dlg", {
31218 // layout config merges with the dialog config
31220 tabPosition: "top",
31221 alwaysShowTabs: true
31224 dialog.addKeyListener(27, dialog.hide, dialog);
31225 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31226 dialog.addButton("Build It!", this.getDownload, this);
31228 // we can even add nested layouts
31229 var innerLayout = new Roo.BorderLayout("dl-inner", {
31239 innerLayout.beginUpdate();
31240 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31241 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31242 innerLayout.endUpdate(true);
31244 var layout = dialog.getLayout();
31245 layout.beginUpdate();
31246 layout.add("center", new Roo.ContentPanel("standard-panel",
31247 {title: "Download the Source", fitToFrame:true}));
31248 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31249 {title: "Build your own roo.js"}));
31250 layout.getRegion("center").showPanel(sp);
31251 layout.endUpdate();
31255 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31256 * @param {Object} config configuration options
31258 Roo.LayoutDialog = function(el, cfg){
31261 if (typeof(cfg) == 'undefined') {
31262 config = Roo.apply({}, el);
31263 // not sure why we use documentElement here.. - it should always be body.
31264 // IE7 borks horribly if we use documentElement.
31265 // webkit also does not like documentElement - it creates a body element...
31266 el = Roo.get( document.body || document.documentElement ).createChild();
31267 //config.autoCreate = true;
31271 config.autoTabs = false;
31272 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31273 this.body.setStyle({overflow:"hidden", position:"relative"});
31274 this.layout = new Roo.BorderLayout(this.body.dom, config);
31275 this.layout.monitorWindowResize = false;
31276 this.el.addClass("x-dlg-auto-layout");
31277 // fix case when center region overwrites center function
31278 this.center = Roo.BasicDialog.prototype.center;
31279 this.on("show", this.layout.layout, this.layout, true);
31280 if (config.items) {
31281 var xitems = config.items;
31282 delete config.items;
31283 Roo.each(xitems, this.addxtype, this);
31288 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31290 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31293 endUpdate : function(){
31294 this.layout.endUpdate();
31298 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31301 beginUpdate : function(){
31302 this.layout.beginUpdate();
31306 * Get the BorderLayout for this dialog
31307 * @return {Roo.BorderLayout}
31309 getLayout : function(){
31310 return this.layout;
31313 showEl : function(){
31314 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31316 this.layout.layout();
31321 // Use the syncHeightBeforeShow config option to control this automatically
31322 syncBodyHeight : function(){
31323 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31324 if(this.layout){this.layout.layout();}
31328 * Add an xtype element (actually adds to the layout.)
31329 * @return {Object} xdata xtype object data.
31332 addxtype : function(c) {
31333 return this.layout.addxtype(c);
31337 * Ext JS Library 1.1.1
31338 * Copyright(c) 2006-2007, Ext JS, LLC.
31340 * Originally Released Under LGPL - original licence link has changed is not relivant.
31343 * <script type="text/javascript">
31347 * @class Roo.MessageBox
31348 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31352 Roo.Msg.alert('Status', 'Changes saved successfully.');
31354 // Prompt for user data:
31355 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31357 // process text value...
31361 // Show a dialog using config options:
31363 title:'Save Changes?',
31364 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31365 buttons: Roo.Msg.YESNOCANCEL,
31372 Roo.MessageBox = function(){
31373 var dlg, opt, mask, waitTimer;
31374 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31375 var buttons, activeTextEl, bwidth;
31378 var handleButton = function(button){
31380 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31384 var handleHide = function(){
31385 if(opt && opt.cls){
31386 dlg.el.removeClass(opt.cls);
31389 Roo.TaskMgr.stop(waitTimer);
31395 var updateButtons = function(b){
31398 buttons["ok"].hide();
31399 buttons["cancel"].hide();
31400 buttons["yes"].hide();
31401 buttons["no"].hide();
31402 dlg.footer.dom.style.display = 'none';
31405 dlg.footer.dom.style.display = '';
31406 for(var k in buttons){
31407 if(typeof buttons[k] != "function"){
31410 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31411 width += buttons[k].el.getWidth()+15;
31421 var handleEsc = function(d, k, e){
31422 if(opt && opt.closable !== false){
31432 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31433 * @return {Roo.BasicDialog} The BasicDialog element
31435 getDialog : function(){
31437 dlg = new Roo.BasicDialog("x-msg-box", {
31442 constraintoviewport:false,
31444 collapsible : false,
31447 width:400, height:100,
31448 buttonAlign:"center",
31449 closeClick : function(){
31450 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31451 handleButton("no");
31453 handleButton("cancel");
31457 dlg.on("hide", handleHide);
31459 dlg.addKeyListener(27, handleEsc);
31461 var bt = this.buttonText;
31462 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31463 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31464 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31465 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31466 bodyEl = dlg.body.createChild({
31468 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>'
31470 msgEl = bodyEl.dom.firstChild;
31471 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31472 textboxEl.enableDisplayMode();
31473 textboxEl.addKeyListener([10,13], function(){
31474 if(dlg.isVisible() && opt && opt.buttons){
31475 if(opt.buttons.ok){
31476 handleButton("ok");
31477 }else if(opt.buttons.yes){
31478 handleButton("yes");
31482 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31483 textareaEl.enableDisplayMode();
31484 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31485 progressEl.enableDisplayMode();
31486 var pf = progressEl.dom.firstChild;
31488 pp = Roo.get(pf.firstChild);
31489 pp.setHeight(pf.offsetHeight);
31497 * Updates the message box body text
31498 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31499 * the XHTML-compliant non-breaking space character '&#160;')
31500 * @return {Roo.MessageBox} This message box
31502 updateText : function(text){
31503 if(!dlg.isVisible() && !opt.width){
31504 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31506 msgEl.innerHTML = text || ' ';
31508 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31509 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31511 Math.min(opt.width || cw , this.maxWidth),
31512 Math.max(opt.minWidth || this.minWidth, bwidth)
31515 activeTextEl.setWidth(w);
31517 if(dlg.isVisible()){
31518 dlg.fixedcenter = false;
31520 // to big, make it scroll. = But as usual stupid IE does not support
31523 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31524 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31525 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31527 bodyEl.dom.style.height = '';
31528 bodyEl.dom.style.overflowY = '';
31531 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31533 bodyEl.dom.style.overflowX = '';
31536 dlg.setContentSize(w, bodyEl.getHeight());
31537 if(dlg.isVisible()){
31538 dlg.fixedcenter = true;
31544 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31545 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31546 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31547 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31548 * @return {Roo.MessageBox} This message box
31550 updateProgress : function(value, text){
31552 this.updateText(text);
31554 if (pp) { // weird bug on my firefox - for some reason this is not defined
31555 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31561 * Returns true if the message box is currently displayed
31562 * @return {Boolean} True if the message box is visible, else false
31564 isVisible : function(){
31565 return dlg && dlg.isVisible();
31569 * Hides the message box if it is displayed
31572 if(this.isVisible()){
31578 * Displays a new message box, or reinitializes an existing message box, based on the config options
31579 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31580 * The following config object properties are supported:
31582 Property Type Description
31583 ---------- --------------- ------------------------------------------------------------------------------------
31584 animEl String/Element An id or Element from which the message box should animate as it opens and
31585 closes (defaults to undefined)
31586 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31587 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31588 closable Boolean False to hide the top-right close button (defaults to true). Note that
31589 progress and wait dialogs will ignore this property and always hide the
31590 close button as they can only be closed programmatically.
31591 cls String A custom CSS class to apply to the message box element
31592 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31593 displayed (defaults to 75)
31594 fn Function A callback function to execute after closing the dialog. The arguments to the
31595 function will be btn (the name of the button that was clicked, if applicable,
31596 e.g. "ok"), and text (the value of the active text field, if applicable).
31597 Progress and wait dialogs will ignore this option since they do not respond to
31598 user actions and can only be closed programmatically, so any required function
31599 should be called by the same code after it closes the dialog.
31600 icon String A CSS class that provides a background image to be used as an icon for
31601 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31602 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31603 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31604 modal Boolean False to allow user interaction with the page while the message box is
31605 displayed (defaults to true)
31606 msg String A string that will replace the existing message box body text (defaults
31607 to the XHTML-compliant non-breaking space character ' ')
31608 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31609 progress Boolean True to display a progress bar (defaults to false)
31610 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31611 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31612 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31613 title String The title text
31614 value String The string value to set into the active textbox element if displayed
31615 wait Boolean True to display a progress bar (defaults to false)
31616 width Number The width of the dialog in pixels
31623 msg: 'Please enter your address:',
31625 buttons: Roo.MessageBox.OKCANCEL,
31628 animEl: 'addAddressBtn'
31631 * @param {Object} config Configuration options
31632 * @return {Roo.MessageBox} This message box
31634 show : function(options)
31637 // this causes nightmares if you show one dialog after another
31638 // especially on callbacks..
31640 if(this.isVisible()){
31643 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31644 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31645 Roo.log("New Dialog Message:" + options.msg )
31646 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31647 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31650 var d = this.getDialog();
31652 d.setTitle(opt.title || " ");
31653 d.close.setDisplayed(opt.closable !== false);
31654 activeTextEl = textboxEl;
31655 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31660 textareaEl.setHeight(typeof opt.multiline == "number" ?
31661 opt.multiline : this.defaultTextHeight);
31662 activeTextEl = textareaEl;
31671 progressEl.setDisplayed(opt.progress === true);
31672 this.updateProgress(0);
31673 activeTextEl.dom.value = opt.value || "";
31675 dlg.setDefaultButton(activeTextEl);
31677 var bs = opt.buttons;
31680 db = buttons["ok"];
31681 }else if(bs && bs.yes){
31682 db = buttons["yes"];
31684 dlg.setDefaultButton(db);
31686 bwidth = updateButtons(opt.buttons);
31687 this.updateText(opt.msg);
31689 d.el.addClass(opt.cls);
31691 d.proxyDrag = opt.proxyDrag === true;
31692 d.modal = opt.modal !== false;
31693 d.mask = opt.modal !== false ? mask : false;
31694 if(!d.isVisible()){
31695 // force it to the end of the z-index stack so it gets a cursor in FF
31696 document.body.appendChild(dlg.el.dom);
31697 d.animateTarget = null;
31698 d.show(options.animEl);
31704 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31705 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31706 * and closing the message box when the process is complete.
31707 * @param {String} title The title bar text
31708 * @param {String} msg The message box body text
31709 * @return {Roo.MessageBox} This message box
31711 progress : function(title, msg){
31718 minWidth: this.minProgressWidth,
31725 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31726 * If a callback function is passed it will be called after the user clicks the button, and the
31727 * id of the button that was clicked will be passed as the only parameter to the callback
31728 * (could also be the top-right close button).
31729 * @param {String} title The title bar text
31730 * @param {String} msg The message box body text
31731 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31732 * @param {Object} scope (optional) The scope of the callback function
31733 * @return {Roo.MessageBox} This message box
31735 alert : function(title, msg, fn, scope){
31748 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31749 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31750 * You are responsible for closing the message box when the process is complete.
31751 * @param {String} msg The message box body text
31752 * @param {String} title (optional) The title bar text
31753 * @return {Roo.MessageBox} This message box
31755 wait : function(msg, title){
31766 waitTimer = Roo.TaskMgr.start({
31768 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31776 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31777 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31778 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31779 * @param {String} title The title bar text
31780 * @param {String} msg The message box body text
31781 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31782 * @param {Object} scope (optional) The scope of the callback function
31783 * @return {Roo.MessageBox} This message box
31785 confirm : function(title, msg, fn, scope){
31789 buttons: this.YESNO,
31798 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31799 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31800 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31801 * (could also be the top-right close button) and the text that was entered will be passed as the two
31802 * parameters to the callback.
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 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31808 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31809 * @return {Roo.MessageBox} This message box
31811 prompt : function(title, msg, fn, scope, multiline){
31815 buttons: this.OKCANCEL,
31820 multiline: multiline,
31827 * Button config that displays a single OK button
31832 * Button config that displays Yes and No buttons
31835 YESNO : {yes:true, no:true},
31837 * Button config that displays OK and Cancel buttons
31840 OKCANCEL : {ok:true, cancel:true},
31842 * Button config that displays Yes, No and Cancel buttons
31845 YESNOCANCEL : {yes:true, no:true, cancel:true},
31848 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31851 defaultTextHeight : 75,
31853 * The maximum width in pixels of the message box (defaults to 600)
31858 * The minimum width in pixels of the message box (defaults to 100)
31863 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31864 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31867 minProgressWidth : 250,
31869 * An object containing the default button text strings that can be overriden for localized language support.
31870 * Supported properties are: ok, cancel, yes and no.
31871 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31884 * Shorthand for {@link Roo.MessageBox}
31886 Roo.Msg = Roo.MessageBox;/*
31888 * Ext JS Library 1.1.1
31889 * Copyright(c) 2006-2007, Ext JS, LLC.
31891 * Originally Released Under LGPL - original licence link has changed is not relivant.
31894 * <script type="text/javascript">
31897 * @class Roo.QuickTips
31898 * Provides attractive and customizable tooltips for any element.
31901 Roo.QuickTips = function(){
31902 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31903 var ce, bd, xy, dd;
31904 var visible = false, disabled = true, inited = false;
31905 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31907 var onOver = function(e){
31911 var t = e.getTarget();
31912 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31915 if(ce && t == ce.el){
31916 clearTimeout(hideProc);
31919 if(t && tagEls[t.id]){
31920 tagEls[t.id].el = t;
31921 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31924 var ttp, et = Roo.fly(t);
31925 var ns = cfg.namespace;
31926 if(tm.interceptTitles && t.title){
31929 t.removeAttribute("title");
31930 e.preventDefault();
31932 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31935 showProc = show.defer(tm.showDelay, tm, [{
31938 width: et.getAttributeNS(ns, cfg.width),
31939 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31940 title: et.getAttributeNS(ns, cfg.title),
31941 cls: et.getAttributeNS(ns, cfg.cls)
31946 var onOut = function(e){
31947 clearTimeout(showProc);
31948 var t = e.getTarget();
31949 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31950 hideProc = setTimeout(hide, tm.hideDelay);
31954 var onMove = function(e){
31960 if(tm.trackMouse && ce){
31965 var onDown = function(e){
31966 clearTimeout(showProc);
31967 clearTimeout(hideProc);
31969 if(tm.hideOnClick){
31972 tm.enable.defer(100, tm);
31977 var getPad = function(){
31978 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31981 var show = function(o){
31985 clearTimeout(dismissProc);
31987 if(removeCls){ // in case manually hidden
31988 el.removeClass(removeCls);
31992 el.addClass(ce.cls);
31993 removeCls = ce.cls;
31996 tipTitle.update(ce.title);
31999 tipTitle.update('');
32002 el.dom.style.width = tm.maxWidth+'px';
32003 //tipBody.dom.style.width = '';
32004 tipBodyText.update(o.text);
32005 var p = getPad(), w = ce.width;
32007 var td = tipBodyText.dom;
32008 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
32009 if(aw > tm.maxWidth){
32011 }else if(aw < tm.minWidth){
32017 //tipBody.setWidth(w);
32018 el.setWidth(parseInt(w, 10) + p);
32019 if(ce.autoHide === false){
32020 close.setDisplayed(true);
32025 close.setDisplayed(false);
32031 el.avoidY = xy[1]-18;
32036 el.setStyle("visibility", "visible");
32037 el.fadeIn({callback: afterShow});
32043 var afterShow = function(){
32047 if(tm.autoDismiss && ce.autoHide !== false){
32048 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32053 var hide = function(noanim){
32054 clearTimeout(dismissProc);
32055 clearTimeout(hideProc);
32057 if(el.isVisible()){
32059 if(noanim !== true && tm.animate){
32060 el.fadeOut({callback: afterHide});
32067 var afterHide = function(){
32070 el.removeClass(removeCls);
32077 * @cfg {Number} minWidth
32078 * The minimum width of the quick tip (defaults to 40)
32082 * @cfg {Number} maxWidth
32083 * The maximum width of the quick tip (defaults to 300)
32087 * @cfg {Boolean} interceptTitles
32088 * True to automatically use the element's DOM title value if available (defaults to false)
32090 interceptTitles : false,
32092 * @cfg {Boolean} trackMouse
32093 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32095 trackMouse : false,
32097 * @cfg {Boolean} hideOnClick
32098 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32100 hideOnClick : true,
32102 * @cfg {Number} showDelay
32103 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32107 * @cfg {Number} hideDelay
32108 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32112 * @cfg {Boolean} autoHide
32113 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32114 * Used in conjunction with hideDelay.
32119 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32120 * (defaults to true). Used in conjunction with autoDismissDelay.
32122 autoDismiss : true,
32125 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32127 autoDismissDelay : 5000,
32129 * @cfg {Boolean} animate
32130 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32135 * @cfg {String} title
32136 * Title text to display (defaults to ''). This can be any valid HTML markup.
32140 * @cfg {String} text
32141 * Body text to display (defaults to ''). This can be any valid HTML markup.
32145 * @cfg {String} cls
32146 * A CSS class to apply to the base quick tip element (defaults to '').
32150 * @cfg {Number} width
32151 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32152 * minWidth or maxWidth.
32157 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32158 * or display QuickTips in a page.
32161 tm = Roo.QuickTips;
32162 cfg = tm.tagConfig;
32164 if(!Roo.isReady){ // allow calling of init() before onReady
32165 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32168 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32169 el.fxDefaults = {stopFx: true};
32170 // maximum custom styling
32171 //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>');
32172 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>');
32173 tipTitle = el.child('h3');
32174 tipTitle.enableDisplayMode("block");
32175 tipBody = el.child('div.x-tip-bd');
32176 tipBodyText = el.child('div.x-tip-bd-inner');
32177 //bdLeft = el.child('div.x-tip-bd-left');
32178 //bdRight = el.child('div.x-tip-bd-right');
32179 close = el.child('div.x-tip-close');
32180 close.enableDisplayMode("block");
32181 close.on("click", hide);
32182 var d = Roo.get(document);
32183 d.on("mousedown", onDown);
32184 d.on("mouseover", onOver);
32185 d.on("mouseout", onOut);
32186 d.on("mousemove", onMove);
32187 esc = d.addKeyListener(27, hide);
32190 dd = el.initDD("default", null, {
32191 onDrag : function(){
32195 dd.setHandleElId(tipTitle.id);
32204 * Configures a new quick tip instance and assigns it to a target element. The following config options
32207 Property Type Description
32208 ---------- --------------------- ------------------------------------------------------------------------
32209 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32211 * @param {Object} config The config object
32213 register : function(config){
32214 var cs = config instanceof Array ? config : arguments;
32215 for(var i = 0, len = cs.length; i < len; i++) {
32217 var target = c.target;
32219 if(target instanceof Array){
32220 for(var j = 0, jlen = target.length; j < jlen; j++){
32221 tagEls[target[j]] = c;
32224 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32231 * Removes this quick tip from its element and destroys it.
32232 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32234 unregister : function(el){
32235 delete tagEls[Roo.id(el)];
32239 * Enable this quick tip.
32241 enable : function(){
32242 if(inited && disabled){
32244 if(locks.length < 1){
32251 * Disable this quick tip.
32253 disable : function(){
32255 clearTimeout(showProc);
32256 clearTimeout(hideProc);
32257 clearTimeout(dismissProc);
32265 * Returns true if the quick tip is enabled, else false.
32267 isEnabled : function(){
32274 attribute : "qtip",
32284 // backwards compat
32285 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32287 * Ext JS Library 1.1.1
32288 * Copyright(c) 2006-2007, Ext JS, LLC.
32290 * Originally Released Under LGPL - original licence link has changed is not relivant.
32293 * <script type="text/javascript">
32298 * @class Roo.tree.TreePanel
32299 * @extends Roo.data.Tree
32301 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32302 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32303 * @cfg {Boolean} enableDD true to enable drag and drop
32304 * @cfg {Boolean} enableDrag true to enable just drag
32305 * @cfg {Boolean} enableDrop true to enable just drop
32306 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32307 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32308 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32309 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32310 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32311 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32312 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32313 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32314 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32315 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32316 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32317 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32318 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32319 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32320 * @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>
32321 * @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>
32324 * @param {String/HTMLElement/Element} el The container element
32325 * @param {Object} config
32327 Roo.tree.TreePanel = function(el, config){
32329 var loader = false;
32331 root = config.root;
32332 delete config.root;
32334 if (config.loader) {
32335 loader = config.loader;
32336 delete config.loader;
32339 Roo.apply(this, config);
32340 Roo.tree.TreePanel.superclass.constructor.call(this);
32341 this.el = Roo.get(el);
32342 this.el.addClass('x-tree');
32343 //console.log(root);
32345 this.setRootNode( Roo.factory(root, Roo.tree));
32348 this.loader = Roo.factory(loader, Roo.tree);
32351 * Read-only. The id of the container element becomes this TreePanel's id.
32353 this.id = this.el.id;
32356 * @event beforeload
32357 * Fires before a node is loaded, return false to cancel
32358 * @param {Node} node The node being loaded
32360 "beforeload" : true,
32363 * Fires when a node is loaded
32364 * @param {Node} node The node that was loaded
32368 * @event textchange
32369 * Fires when the text for a node is changed
32370 * @param {Node} node The node
32371 * @param {String} text The new text
32372 * @param {String} oldText The old text
32374 "textchange" : true,
32376 * @event beforeexpand
32377 * Fires before a node is expanded, return false to cancel.
32378 * @param {Node} node The node
32379 * @param {Boolean} deep
32380 * @param {Boolean} anim
32382 "beforeexpand" : true,
32384 * @event beforecollapse
32385 * Fires before a node is collapsed, return false to cancel.
32386 * @param {Node} node The node
32387 * @param {Boolean} deep
32388 * @param {Boolean} anim
32390 "beforecollapse" : true,
32393 * Fires when a node is expanded
32394 * @param {Node} node The node
32398 * @event disabledchange
32399 * Fires when the disabled status of a node changes
32400 * @param {Node} node The node
32401 * @param {Boolean} disabled
32403 "disabledchange" : true,
32406 * Fires when a node is collapsed
32407 * @param {Node} node The node
32411 * @event beforeclick
32412 * Fires before click processing on a node. Return false to cancel the default action.
32413 * @param {Node} node The node
32414 * @param {Roo.EventObject} e The event object
32416 "beforeclick":true,
32418 * @event checkchange
32419 * Fires when a node with a checkbox's checked property changes
32420 * @param {Node} this This node
32421 * @param {Boolean} checked
32423 "checkchange":true,
32426 * Fires when a node is clicked
32427 * @param {Node} node The node
32428 * @param {Roo.EventObject} e The event object
32433 * Fires when a node is double clicked
32434 * @param {Node} node The node
32435 * @param {Roo.EventObject} e The event object
32439 * @event contextmenu
32440 * Fires when a node is right clicked
32441 * @param {Node} node The node
32442 * @param {Roo.EventObject} e The event object
32444 "contextmenu":true,
32446 * @event beforechildrenrendered
32447 * Fires right before the child nodes for a node are rendered
32448 * @param {Node} node The node
32450 "beforechildrenrendered":true,
32453 * Fires when a node starts being dragged
32454 * @param {Roo.tree.TreePanel} this
32455 * @param {Roo.tree.TreeNode} node
32456 * @param {event} e The raw browser event
32458 "startdrag" : true,
32461 * Fires when a drag operation is complete
32462 * @param {Roo.tree.TreePanel} this
32463 * @param {Roo.tree.TreeNode} node
32464 * @param {event} e The raw browser event
32469 * Fires when a dragged node is dropped on a valid DD target
32470 * @param {Roo.tree.TreePanel} this
32471 * @param {Roo.tree.TreeNode} node
32472 * @param {DD} dd The dd it was dropped on
32473 * @param {event} e The raw browser event
32477 * @event beforenodedrop
32478 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32479 * passed to handlers has the following properties:<br />
32480 * <ul style="padding:5px;padding-left:16px;">
32481 * <li>tree - The TreePanel</li>
32482 * <li>target - The node being targeted for the drop</li>
32483 * <li>data - The drag data from the drag source</li>
32484 * <li>point - The point of the drop - append, above or below</li>
32485 * <li>source - The drag source</li>
32486 * <li>rawEvent - Raw mouse event</li>
32487 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32488 * to be inserted by setting them on this object.</li>
32489 * <li>cancel - Set this to true to cancel the drop.</li>
32491 * @param {Object} dropEvent
32493 "beforenodedrop" : true,
32496 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32497 * passed to handlers has the following properties:<br />
32498 * <ul style="padding:5px;padding-left:16px;">
32499 * <li>tree - The TreePanel</li>
32500 * <li>target - The node being targeted for the drop</li>
32501 * <li>data - The drag data from the drag source</li>
32502 * <li>point - The point of the drop - append, above or below</li>
32503 * <li>source - The drag source</li>
32504 * <li>rawEvent - Raw mouse event</li>
32505 * <li>dropNode - Dropped node(s).</li>
32507 * @param {Object} dropEvent
32511 * @event nodedragover
32512 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32513 * passed to handlers has the following properties:<br />
32514 * <ul style="padding:5px;padding-left:16px;">
32515 * <li>tree - The TreePanel</li>
32516 * <li>target - The node being targeted for the drop</li>
32517 * <li>data - The drag data from the drag source</li>
32518 * <li>point - The point of the drop - append, above or below</li>
32519 * <li>source - The drag source</li>
32520 * <li>rawEvent - Raw mouse event</li>
32521 * <li>dropNode - Drop node(s) provided by the source.</li>
32522 * <li>cancel - Set this to true to signal drop not allowed.</li>
32524 * @param {Object} dragOverEvent
32526 "nodedragover" : true
32529 if(this.singleExpand){
32530 this.on("beforeexpand", this.restrictExpand, this);
32533 this.editor.tree = this;
32534 this.editor = Roo.factory(this.editor, Roo.tree);
32537 if (this.selModel) {
32538 this.selModel = Roo.factory(this.selModel, Roo.tree);
32542 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32543 rootVisible : true,
32544 animate: Roo.enableFx,
32547 hlDrop : Roo.enableFx,
32551 rendererTip: false,
32553 restrictExpand : function(node){
32554 var p = node.parentNode;
32556 if(p.expandedChild && p.expandedChild.parentNode == p){
32557 p.expandedChild.collapse();
32559 p.expandedChild = node;
32563 // private override
32564 setRootNode : function(node){
32565 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32566 if(!this.rootVisible){
32567 node.ui = new Roo.tree.RootTreeNodeUI(node);
32573 * Returns the container element for this TreePanel
32575 getEl : function(){
32580 * Returns the default TreeLoader for this TreePanel
32582 getLoader : function(){
32583 return this.loader;
32589 expandAll : function(){
32590 this.root.expand(true);
32594 * Collapse all nodes
32596 collapseAll : function(){
32597 this.root.collapse(true);
32601 * Returns the selection model used by this TreePanel
32603 getSelectionModel : function(){
32604 if(!this.selModel){
32605 this.selModel = new Roo.tree.DefaultSelectionModel();
32607 return this.selModel;
32611 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32612 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32613 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32616 getChecked : function(a, startNode){
32617 startNode = startNode || this.root;
32619 var f = function(){
32620 if(this.attributes.checked){
32621 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32624 startNode.cascade(f);
32629 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32630 * @param {String} path
32631 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32632 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32633 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32635 expandPath : function(path, attr, callback){
32636 attr = attr || "id";
32637 var keys = path.split(this.pathSeparator);
32638 var curNode = this.root;
32639 if(curNode.attributes[attr] != keys[1]){ // invalid root
32641 callback(false, null);
32646 var f = function(){
32647 if(++index == keys.length){
32649 callback(true, curNode);
32653 var c = curNode.findChild(attr, keys[index]);
32656 callback(false, curNode);
32661 c.expand(false, false, f);
32663 curNode.expand(false, false, f);
32667 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32668 * @param {String} path
32669 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32670 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32671 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32673 selectPath : function(path, attr, callback){
32674 attr = attr || "id";
32675 var keys = path.split(this.pathSeparator);
32676 var v = keys.pop();
32677 if(keys.length > 0){
32678 var f = function(success, node){
32679 if(success && node){
32680 var n = node.findChild(attr, v);
32686 }else if(callback){
32687 callback(false, n);
32691 callback(false, n);
32695 this.expandPath(keys.join(this.pathSeparator), attr, f);
32697 this.root.select();
32699 callback(true, this.root);
32704 getTreeEl : function(){
32709 * Trigger rendering of this TreePanel
32711 render : function(){
32712 if (this.innerCt) {
32713 return this; // stop it rendering more than once!!
32716 this.innerCt = this.el.createChild({tag:"ul",
32717 cls:"x-tree-root-ct " +
32718 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32720 if(this.containerScroll){
32721 Roo.dd.ScrollManager.register(this.el);
32723 if((this.enableDD || this.enableDrop) && !this.dropZone){
32725 * The dropZone used by this tree if drop is enabled
32726 * @type Roo.tree.TreeDropZone
32728 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32729 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32732 if((this.enableDD || this.enableDrag) && !this.dragZone){
32734 * The dragZone used by this tree if drag is enabled
32735 * @type Roo.tree.TreeDragZone
32737 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32738 ddGroup: this.ddGroup || "TreeDD",
32739 scroll: this.ddScroll
32742 this.getSelectionModel().init(this);
32744 Roo.log("ROOT not set in tree");
32747 this.root.render();
32748 if(!this.rootVisible){
32749 this.root.renderChildren();
32755 * Ext JS Library 1.1.1
32756 * Copyright(c) 2006-2007, Ext JS, LLC.
32758 * Originally Released Under LGPL - original licence link has changed is not relivant.
32761 * <script type="text/javascript">
32766 * @class Roo.tree.DefaultSelectionModel
32767 * @extends Roo.util.Observable
32768 * The default single selection for a TreePanel.
32769 * @param {Object} cfg Configuration
32771 Roo.tree.DefaultSelectionModel = function(cfg){
32772 this.selNode = null;
32778 * @event selectionchange
32779 * Fires when the selected node changes
32780 * @param {DefaultSelectionModel} this
32781 * @param {TreeNode} node the new selection
32783 "selectionchange" : true,
32786 * @event beforeselect
32787 * Fires before the selected node changes, return false to cancel the change
32788 * @param {DefaultSelectionModel} this
32789 * @param {TreeNode} node the new selection
32790 * @param {TreeNode} node the old selection
32792 "beforeselect" : true
32795 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32798 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32799 init : function(tree){
32801 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32802 tree.on("click", this.onNodeClick, this);
32805 onNodeClick : function(node, e){
32806 if (e.ctrlKey && this.selNode == node) {
32807 this.unselect(node);
32815 * @param {TreeNode} node The node to select
32816 * @return {TreeNode} The selected node
32818 select : function(node){
32819 var last = this.selNode;
32820 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32822 last.ui.onSelectedChange(false);
32824 this.selNode = node;
32825 node.ui.onSelectedChange(true);
32826 this.fireEvent("selectionchange", this, node, last);
32833 * @param {TreeNode} node The node to unselect
32835 unselect : function(node){
32836 if(this.selNode == node){
32837 this.clearSelections();
32842 * Clear all selections
32844 clearSelections : function(){
32845 var n = this.selNode;
32847 n.ui.onSelectedChange(false);
32848 this.selNode = null;
32849 this.fireEvent("selectionchange", this, null);
32855 * Get the selected node
32856 * @return {TreeNode} The selected node
32858 getSelectedNode : function(){
32859 return this.selNode;
32863 * Returns true if the node is selected
32864 * @param {TreeNode} node The node to check
32865 * @return {Boolean}
32867 isSelected : function(node){
32868 return this.selNode == node;
32872 * Selects the node above the selected node in the tree, intelligently walking the nodes
32873 * @return TreeNode The new selection
32875 selectPrevious : function(){
32876 var s = this.selNode || this.lastSelNode;
32880 var ps = s.previousSibling;
32882 if(!ps.isExpanded() || ps.childNodes.length < 1){
32883 return this.select(ps);
32885 var lc = ps.lastChild;
32886 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32889 return this.select(lc);
32891 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32892 return this.select(s.parentNode);
32898 * Selects the node above the selected node in the tree, intelligently walking the nodes
32899 * @return TreeNode The new selection
32901 selectNext : function(){
32902 var s = this.selNode || this.lastSelNode;
32906 if(s.firstChild && s.isExpanded()){
32907 return this.select(s.firstChild);
32908 }else if(s.nextSibling){
32909 return this.select(s.nextSibling);
32910 }else if(s.parentNode){
32912 s.parentNode.bubble(function(){
32913 if(this.nextSibling){
32914 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32923 onKeyDown : function(e){
32924 var s = this.selNode || this.lastSelNode;
32925 // undesirable, but required
32930 var k = e.getKey();
32938 this.selectPrevious();
32941 e.preventDefault();
32942 if(s.hasChildNodes()){
32943 if(!s.isExpanded()){
32945 }else if(s.firstChild){
32946 this.select(s.firstChild, e);
32951 e.preventDefault();
32952 if(s.hasChildNodes() && s.isExpanded()){
32954 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32955 this.select(s.parentNode, e);
32963 * @class Roo.tree.MultiSelectionModel
32964 * @extends Roo.util.Observable
32965 * Multi selection for a TreePanel.
32966 * @param {Object} cfg Configuration
32968 Roo.tree.MultiSelectionModel = function(){
32969 this.selNodes = [];
32973 * @event selectionchange
32974 * Fires when the selected nodes change
32975 * @param {MultiSelectionModel} this
32976 * @param {Array} nodes Array of the selected nodes
32978 "selectionchange" : true
32980 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32984 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32985 init : function(tree){
32987 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32988 tree.on("click", this.onNodeClick, this);
32991 onNodeClick : function(node, e){
32992 this.select(node, e, e.ctrlKey);
32997 * @param {TreeNode} node The node to select
32998 * @param {EventObject} e (optional) An event associated with the selection
32999 * @param {Boolean} keepExisting True to retain existing selections
33000 * @return {TreeNode} The selected node
33002 select : function(node, e, keepExisting){
33003 if(keepExisting !== true){
33004 this.clearSelections(true);
33006 if(this.isSelected(node)){
33007 this.lastSelNode = node;
33010 this.selNodes.push(node);
33011 this.selMap[node.id] = node;
33012 this.lastSelNode = node;
33013 node.ui.onSelectedChange(true);
33014 this.fireEvent("selectionchange", this, this.selNodes);
33020 * @param {TreeNode} node The node to unselect
33022 unselect : function(node){
33023 if(this.selMap[node.id]){
33024 node.ui.onSelectedChange(false);
33025 var sn = this.selNodes;
33028 index = sn.indexOf(node);
33030 for(var i = 0, len = sn.length; i < len; i++){
33038 this.selNodes.splice(index, 1);
33040 delete this.selMap[node.id];
33041 this.fireEvent("selectionchange", this, this.selNodes);
33046 * Clear all selections
33048 clearSelections : function(suppressEvent){
33049 var sn = this.selNodes;
33051 for(var i = 0, len = sn.length; i < len; i++){
33052 sn[i].ui.onSelectedChange(false);
33054 this.selNodes = [];
33056 if(suppressEvent !== true){
33057 this.fireEvent("selectionchange", this, this.selNodes);
33063 * Returns true if the node is selected
33064 * @param {TreeNode} node The node to check
33065 * @return {Boolean}
33067 isSelected : function(node){
33068 return this.selMap[node.id] ? true : false;
33072 * Returns an array of the selected nodes
33075 getSelectedNodes : function(){
33076 return this.selNodes;
33079 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33081 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33083 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33086 * Ext JS Library 1.1.1
33087 * Copyright(c) 2006-2007, Ext JS, LLC.
33089 * Originally Released Under LGPL - original licence link has changed is not relivant.
33092 * <script type="text/javascript">
33096 * @class Roo.tree.TreeNode
33097 * @extends Roo.data.Node
33098 * @cfg {String} text The text for this node
33099 * @cfg {Boolean} expanded true to start the node expanded
33100 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33101 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33102 * @cfg {Boolean} disabled true to start the node disabled
33103 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33104 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33105 * @cfg {String} cls A css class to be added to the node
33106 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33107 * @cfg {String} href URL of the link used for the node (defaults to #)
33108 * @cfg {String} hrefTarget target frame for the link
33109 * @cfg {String} qtip An Ext QuickTip for the node
33110 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33111 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33112 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33113 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33114 * (defaults to undefined with no checkbox rendered)
33116 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33118 Roo.tree.TreeNode = function(attributes){
33119 attributes = attributes || {};
33120 if(typeof attributes == "string"){
33121 attributes = {text: attributes};
33123 this.childrenRendered = false;
33124 this.rendered = false;
33125 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33126 this.expanded = attributes.expanded === true;
33127 this.isTarget = attributes.isTarget !== false;
33128 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33129 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33132 * Read-only. The text for this node. To change it use setText().
33135 this.text = attributes.text;
33137 * True if this node is disabled.
33140 this.disabled = attributes.disabled === true;
33144 * @event textchange
33145 * Fires when the text for this node is changed
33146 * @param {Node} this This node
33147 * @param {String} text The new text
33148 * @param {String} oldText The old text
33150 "textchange" : true,
33152 * @event beforeexpand
33153 * Fires before this node is expanded, return false to cancel.
33154 * @param {Node} this This node
33155 * @param {Boolean} deep
33156 * @param {Boolean} anim
33158 "beforeexpand" : true,
33160 * @event beforecollapse
33161 * Fires before this node is collapsed, return false to cancel.
33162 * @param {Node} this This node
33163 * @param {Boolean} deep
33164 * @param {Boolean} anim
33166 "beforecollapse" : true,
33169 * Fires when this node is expanded
33170 * @param {Node} this This node
33174 * @event disabledchange
33175 * Fires when the disabled status of this node changes
33176 * @param {Node} this This node
33177 * @param {Boolean} disabled
33179 "disabledchange" : true,
33182 * Fires when this node is collapsed
33183 * @param {Node} this This node
33187 * @event beforeclick
33188 * Fires before click processing. Return false to cancel the default action.
33189 * @param {Node} this This node
33190 * @param {Roo.EventObject} e The event object
33192 "beforeclick":true,
33194 * @event checkchange
33195 * Fires when a node with a checkbox's checked property changes
33196 * @param {Node} this This node
33197 * @param {Boolean} checked
33199 "checkchange":true,
33202 * Fires when this node is clicked
33203 * @param {Node} this This node
33204 * @param {Roo.EventObject} e The event object
33209 * Fires when this node is double clicked
33210 * @param {Node} this This node
33211 * @param {Roo.EventObject} e The event object
33215 * @event contextmenu
33216 * Fires when this node is right clicked
33217 * @param {Node} this This node
33218 * @param {Roo.EventObject} e The event object
33220 "contextmenu":true,
33222 * @event beforechildrenrendered
33223 * Fires right before the child nodes for this node are rendered
33224 * @param {Node} this This node
33226 "beforechildrenrendered":true
33229 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33232 * Read-only. The UI for this node
33235 this.ui = new uiClass(this);
33237 // finally support items[]
33238 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33243 Roo.each(this.attributes.items, function(c) {
33244 this.appendChild(Roo.factory(c,Roo.Tree));
33246 delete this.attributes.items;
33251 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33252 preventHScroll: true,
33254 * Returns true if this node is expanded
33255 * @return {Boolean}
33257 isExpanded : function(){
33258 return this.expanded;
33262 * Returns the UI object for this node
33263 * @return {TreeNodeUI}
33265 getUI : function(){
33269 // private override
33270 setFirstChild : function(node){
33271 var of = this.firstChild;
33272 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33273 if(this.childrenRendered && of && node != of){
33274 of.renderIndent(true, true);
33277 this.renderIndent(true, true);
33281 // private override
33282 setLastChild : function(node){
33283 var ol = this.lastChild;
33284 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33285 if(this.childrenRendered && ol && node != ol){
33286 ol.renderIndent(true, true);
33289 this.renderIndent(true, true);
33293 // these methods are overridden to provide lazy rendering support
33294 // private override
33295 appendChild : function()
33297 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33298 if(node && this.childrenRendered){
33301 this.ui.updateExpandIcon();
33305 // private override
33306 removeChild : function(node){
33307 this.ownerTree.getSelectionModel().unselect(node);
33308 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33309 // if it's been rendered remove dom node
33310 if(this.childrenRendered){
33313 if(this.childNodes.length < 1){
33314 this.collapse(false, false);
33316 this.ui.updateExpandIcon();
33318 if(!this.firstChild) {
33319 this.childrenRendered = false;
33324 // private override
33325 insertBefore : function(node, refNode){
33326 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33327 if(newNode && refNode && this.childrenRendered){
33330 this.ui.updateExpandIcon();
33335 * Sets the text for this node
33336 * @param {String} text
33338 setText : function(text){
33339 var oldText = this.text;
33341 this.attributes.text = text;
33342 if(this.rendered){ // event without subscribing
33343 this.ui.onTextChange(this, text, oldText);
33345 this.fireEvent("textchange", this, text, oldText);
33349 * Triggers selection of this node
33351 select : function(){
33352 this.getOwnerTree().getSelectionModel().select(this);
33356 * Triggers deselection of this node
33358 unselect : function(){
33359 this.getOwnerTree().getSelectionModel().unselect(this);
33363 * Returns true if this node is selected
33364 * @return {Boolean}
33366 isSelected : function(){
33367 return this.getOwnerTree().getSelectionModel().isSelected(this);
33371 * Expand this node.
33372 * @param {Boolean} deep (optional) True to expand all children as well
33373 * @param {Boolean} anim (optional) false to cancel the default animation
33374 * @param {Function} callback (optional) A callback to be called when
33375 * expanding this node completes (does not wait for deep expand to complete).
33376 * Called with 1 parameter, this node.
33378 expand : function(deep, anim, callback){
33379 if(!this.expanded){
33380 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33383 if(!this.childrenRendered){
33384 this.renderChildren();
33386 this.expanded = true;
33387 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33388 this.ui.animExpand(function(){
33389 this.fireEvent("expand", this);
33390 if(typeof callback == "function"){
33394 this.expandChildNodes(true);
33396 }.createDelegate(this));
33400 this.fireEvent("expand", this);
33401 if(typeof callback == "function"){
33406 if(typeof callback == "function"){
33411 this.expandChildNodes(true);
33415 isHiddenRoot : function(){
33416 return this.isRoot && !this.getOwnerTree().rootVisible;
33420 * Collapse this node.
33421 * @param {Boolean} deep (optional) True to collapse all children as well
33422 * @param {Boolean} anim (optional) false to cancel the default animation
33424 collapse : function(deep, anim){
33425 if(this.expanded && !this.isHiddenRoot()){
33426 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33429 this.expanded = false;
33430 if((this.getOwnerTree().animate && anim !== false) || anim){
33431 this.ui.animCollapse(function(){
33432 this.fireEvent("collapse", this);
33434 this.collapseChildNodes(true);
33436 }.createDelegate(this));
33439 this.ui.collapse();
33440 this.fireEvent("collapse", this);
33444 var cs = this.childNodes;
33445 for(var i = 0, len = cs.length; i < len; i++) {
33446 cs[i].collapse(true, false);
33452 delayedExpand : function(delay){
33453 if(!this.expandProcId){
33454 this.expandProcId = this.expand.defer(delay, this);
33459 cancelExpand : function(){
33460 if(this.expandProcId){
33461 clearTimeout(this.expandProcId);
33463 this.expandProcId = false;
33467 * Toggles expanded/collapsed state of the node
33469 toggle : function(){
33478 * Ensures all parent nodes are expanded
33480 ensureVisible : function(callback){
33481 var tree = this.getOwnerTree();
33482 tree.expandPath(this.parentNode.getPath(), false, function(){
33483 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33484 Roo.callback(callback);
33485 }.createDelegate(this));
33489 * Expand all child nodes
33490 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33492 expandChildNodes : function(deep){
33493 var cs = this.childNodes;
33494 for(var i = 0, len = cs.length; i < len; i++) {
33495 cs[i].expand(deep);
33500 * Collapse all child nodes
33501 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33503 collapseChildNodes : function(deep){
33504 var cs = this.childNodes;
33505 for(var i = 0, len = cs.length; i < len; i++) {
33506 cs[i].collapse(deep);
33511 * Disables this node
33513 disable : function(){
33514 this.disabled = true;
33516 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33517 this.ui.onDisableChange(this, true);
33519 this.fireEvent("disabledchange", this, true);
33523 * Enables this node
33525 enable : function(){
33526 this.disabled = false;
33527 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33528 this.ui.onDisableChange(this, false);
33530 this.fireEvent("disabledchange", this, false);
33534 renderChildren : function(suppressEvent){
33535 if(suppressEvent !== false){
33536 this.fireEvent("beforechildrenrendered", this);
33538 var cs = this.childNodes;
33539 for(var i = 0, len = cs.length; i < len; i++){
33540 cs[i].render(true);
33542 this.childrenRendered = true;
33546 sort : function(fn, scope){
33547 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33548 if(this.childrenRendered){
33549 var cs = this.childNodes;
33550 for(var i = 0, len = cs.length; i < len; i++){
33551 cs[i].render(true);
33557 render : function(bulkRender){
33558 this.ui.render(bulkRender);
33559 if(!this.rendered){
33560 this.rendered = true;
33562 this.expanded = false;
33563 this.expand(false, false);
33569 renderIndent : function(deep, refresh){
33571 this.ui.childIndent = null;
33573 this.ui.renderIndent();
33574 if(deep === true && this.childrenRendered){
33575 var cs = this.childNodes;
33576 for(var i = 0, len = cs.length; i < len; i++){
33577 cs[i].renderIndent(true, refresh);
33583 * Ext JS Library 1.1.1
33584 * Copyright(c) 2006-2007, Ext JS, LLC.
33586 * Originally Released Under LGPL - original licence link has changed is not relivant.
33589 * <script type="text/javascript">
33593 * @class Roo.tree.AsyncTreeNode
33594 * @extends Roo.tree.TreeNode
33595 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33597 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33599 Roo.tree.AsyncTreeNode = function(config){
33600 this.loaded = false;
33601 this.loading = false;
33602 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33604 * @event beforeload
33605 * Fires before this node is loaded, return false to cancel
33606 * @param {Node} this This node
33608 this.addEvents({'beforeload':true, 'load': true});
33611 * Fires when this node is loaded
33612 * @param {Node} this This node
33615 * The loader used by this node (defaults to using the tree's defined loader)
33620 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33621 expand : function(deep, anim, callback){
33622 if(this.loading){ // if an async load is already running, waiting til it's done
33624 var f = function(){
33625 if(!this.loading){ // done loading
33626 clearInterval(timer);
33627 this.expand(deep, anim, callback);
33629 }.createDelegate(this);
33630 timer = setInterval(f, 200);
33634 if(this.fireEvent("beforeload", this) === false){
33637 this.loading = true;
33638 this.ui.beforeLoad(this);
33639 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33641 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33645 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33649 * Returns true if this node is currently loading
33650 * @return {Boolean}
33652 isLoading : function(){
33653 return this.loading;
33656 loadComplete : function(deep, anim, callback){
33657 this.loading = false;
33658 this.loaded = true;
33659 this.ui.afterLoad(this);
33660 this.fireEvent("load", this);
33661 this.expand(deep, anim, callback);
33665 * Returns true if this node has been loaded
33666 * @return {Boolean}
33668 isLoaded : function(){
33669 return this.loaded;
33672 hasChildNodes : function(){
33673 if(!this.isLeaf() && !this.loaded){
33676 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33681 * Trigger a reload for this node
33682 * @param {Function} callback
33684 reload : function(callback){
33685 this.collapse(false, false);
33686 while(this.firstChild){
33687 this.removeChild(this.firstChild);
33689 this.childrenRendered = false;
33690 this.loaded = false;
33691 if(this.isHiddenRoot()){
33692 this.expanded = false;
33694 this.expand(false, false, callback);
33698 * Ext JS Library 1.1.1
33699 * Copyright(c) 2006-2007, Ext JS, LLC.
33701 * Originally Released Under LGPL - original licence link has changed is not relivant.
33704 * <script type="text/javascript">
33708 * @class Roo.tree.TreeNodeUI
33710 * @param {Object} node The node to render
33711 * The TreeNode UI implementation is separate from the
33712 * tree implementation. Unless you are customizing the tree UI,
33713 * you should never have to use this directly.
33715 Roo.tree.TreeNodeUI = function(node){
33717 this.rendered = false;
33718 this.animating = false;
33719 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33722 Roo.tree.TreeNodeUI.prototype = {
33723 removeChild : function(node){
33725 this.ctNode.removeChild(node.ui.getEl());
33729 beforeLoad : function(){
33730 this.addClass("x-tree-node-loading");
33733 afterLoad : function(){
33734 this.removeClass("x-tree-node-loading");
33737 onTextChange : function(node, text, oldText){
33739 this.textNode.innerHTML = text;
33743 onDisableChange : function(node, state){
33744 this.disabled = state;
33746 this.addClass("x-tree-node-disabled");
33748 this.removeClass("x-tree-node-disabled");
33752 onSelectedChange : function(state){
33755 this.addClass("x-tree-selected");
33758 this.removeClass("x-tree-selected");
33762 onMove : function(tree, node, oldParent, newParent, index, refNode){
33763 this.childIndent = null;
33765 var targetNode = newParent.ui.getContainer();
33766 if(!targetNode){//target not rendered
33767 this.holder = document.createElement("div");
33768 this.holder.appendChild(this.wrap);
33771 var insertBefore = refNode ? refNode.ui.getEl() : null;
33773 targetNode.insertBefore(this.wrap, insertBefore);
33775 targetNode.appendChild(this.wrap);
33777 this.node.renderIndent(true);
33781 addClass : function(cls){
33783 Roo.fly(this.elNode).addClass(cls);
33787 removeClass : function(cls){
33789 Roo.fly(this.elNode).removeClass(cls);
33793 remove : function(){
33795 this.holder = document.createElement("div");
33796 this.holder.appendChild(this.wrap);
33800 fireEvent : function(){
33801 return this.node.fireEvent.apply(this.node, arguments);
33804 initEvents : function(){
33805 this.node.on("move", this.onMove, this);
33806 var E = Roo.EventManager;
33807 var a = this.anchor;
33809 var el = Roo.fly(a, '_treeui');
33811 if(Roo.isOpera){ // opera render bug ignores the CSS
33812 el.setStyle("text-decoration", "none");
33815 el.on("click", this.onClick, this);
33816 el.on("dblclick", this.onDblClick, this);
33819 Roo.EventManager.on(this.checkbox,
33820 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33823 el.on("contextmenu", this.onContextMenu, this);
33825 var icon = Roo.fly(this.iconNode);
33826 icon.on("click", this.onClick, this);
33827 icon.on("dblclick", this.onDblClick, this);
33828 icon.on("contextmenu", this.onContextMenu, this);
33829 E.on(this.ecNode, "click", this.ecClick, this, true);
33831 if(this.node.disabled){
33832 this.addClass("x-tree-node-disabled");
33834 if(this.node.hidden){
33835 this.addClass("x-tree-node-disabled");
33837 var ot = this.node.getOwnerTree();
33838 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33839 if(dd && (!this.node.isRoot || ot.rootVisible)){
33840 Roo.dd.Registry.register(this.elNode, {
33842 handles: this.getDDHandles(),
33848 getDDHandles : function(){
33849 return [this.iconNode, this.textNode];
33854 this.wrap.style.display = "none";
33860 this.wrap.style.display = "";
33864 onContextMenu : function(e){
33865 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33866 e.preventDefault();
33868 this.fireEvent("contextmenu", this.node, e);
33872 onClick : function(e){
33877 if(this.fireEvent("beforeclick", this.node, e) !== false){
33878 if(!this.disabled && this.node.attributes.href){
33879 this.fireEvent("click", this.node, e);
33882 e.preventDefault();
33887 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33888 this.node.toggle();
33891 this.fireEvent("click", this.node, e);
33897 onDblClick : function(e){
33898 e.preventDefault();
33903 this.toggleCheck();
33905 if(!this.animating && this.node.hasChildNodes()){
33906 this.node.toggle();
33908 this.fireEvent("dblclick", this.node, e);
33911 onCheckChange : function(){
33912 var checked = this.checkbox.checked;
33913 this.node.attributes.checked = checked;
33914 this.fireEvent('checkchange', this.node, checked);
33917 ecClick : function(e){
33918 if(!this.animating && this.node.hasChildNodes()){
33919 this.node.toggle();
33923 startDrop : function(){
33924 this.dropping = true;
33927 // delayed drop so the click event doesn't get fired on a drop
33928 endDrop : function(){
33929 setTimeout(function(){
33930 this.dropping = false;
33931 }.createDelegate(this), 50);
33934 expand : function(){
33935 this.updateExpandIcon();
33936 this.ctNode.style.display = "";
33939 focus : function(){
33940 if(!this.node.preventHScroll){
33941 try{this.anchor.focus();
33943 }else if(!Roo.isIE){
33945 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33946 var l = noscroll.scrollLeft;
33947 this.anchor.focus();
33948 noscroll.scrollLeft = l;
33953 toggleCheck : function(value){
33954 var cb = this.checkbox;
33956 cb.checked = (value === undefined ? !cb.checked : value);
33962 this.anchor.blur();
33966 animExpand : function(callback){
33967 var ct = Roo.get(this.ctNode);
33969 if(!this.node.hasChildNodes()){
33970 this.updateExpandIcon();
33971 this.ctNode.style.display = "";
33972 Roo.callback(callback);
33975 this.animating = true;
33976 this.updateExpandIcon();
33979 callback : function(){
33980 this.animating = false;
33981 Roo.callback(callback);
33984 duration: this.node.ownerTree.duration || .25
33988 highlight : function(){
33989 var tree = this.node.getOwnerTree();
33990 Roo.fly(this.wrap).highlight(
33991 tree.hlColor || "C3DAF9",
33992 {endColor: tree.hlBaseColor}
33996 collapse : function(){
33997 this.updateExpandIcon();
33998 this.ctNode.style.display = "none";
34001 animCollapse : function(callback){
34002 var ct = Roo.get(this.ctNode);
34003 ct.enableDisplayMode('block');
34006 this.animating = true;
34007 this.updateExpandIcon();
34010 callback : function(){
34011 this.animating = false;
34012 Roo.callback(callback);
34015 duration: this.node.ownerTree.duration || .25
34019 getContainer : function(){
34020 return this.ctNode;
34023 getEl : function(){
34027 appendDDGhost : function(ghostNode){
34028 ghostNode.appendChild(this.elNode.cloneNode(true));
34031 getDDRepairXY : function(){
34032 return Roo.lib.Dom.getXY(this.iconNode);
34035 onRender : function(){
34039 render : function(bulkRender){
34040 var n = this.node, a = n.attributes;
34041 var targetNode = n.parentNode ?
34042 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34044 if(!this.rendered){
34045 this.rendered = true;
34047 this.renderElements(n, a, targetNode, bulkRender);
34050 if(this.textNode.setAttributeNS){
34051 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34053 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34056 this.textNode.setAttribute("ext:qtip", a.qtip);
34058 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34061 }else if(a.qtipCfg){
34062 a.qtipCfg.target = Roo.id(this.textNode);
34063 Roo.QuickTips.register(a.qtipCfg);
34066 if(!this.node.expanded){
34067 this.updateExpandIcon();
34070 if(bulkRender === true) {
34071 targetNode.appendChild(this.wrap);
34076 renderElements : function(n, a, targetNode, bulkRender)
34078 // add some indent caching, this helps performance when rendering a large tree
34079 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34080 var t = n.getOwnerTree();
34081 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34082 if (typeof(n.attributes.html) != 'undefined') {
34083 txt = n.attributes.html;
34085 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34086 var cb = typeof a.checked == 'boolean';
34087 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34088 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34089 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34090 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34091 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34092 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34093 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34094 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34095 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34096 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34099 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34100 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34101 n.nextSibling.ui.getEl(), buf.join(""));
34103 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34106 this.elNode = this.wrap.childNodes[0];
34107 this.ctNode = this.wrap.childNodes[1];
34108 var cs = this.elNode.childNodes;
34109 this.indentNode = cs[0];
34110 this.ecNode = cs[1];
34111 this.iconNode = cs[2];
34114 this.checkbox = cs[3];
34117 this.anchor = cs[index];
34118 this.textNode = cs[index].firstChild;
34121 getAnchor : function(){
34122 return this.anchor;
34125 getTextEl : function(){
34126 return this.textNode;
34129 getIconEl : function(){
34130 return this.iconNode;
34133 isChecked : function(){
34134 return this.checkbox ? this.checkbox.checked : false;
34137 updateExpandIcon : function(){
34139 var n = this.node, c1, c2;
34140 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34141 var hasChild = n.hasChildNodes();
34145 c1 = "x-tree-node-collapsed";
34146 c2 = "x-tree-node-expanded";
34149 c1 = "x-tree-node-expanded";
34150 c2 = "x-tree-node-collapsed";
34153 this.removeClass("x-tree-node-leaf");
34154 this.wasLeaf = false;
34156 if(this.c1 != c1 || this.c2 != c2){
34157 Roo.fly(this.elNode).replaceClass(c1, c2);
34158 this.c1 = c1; this.c2 = c2;
34161 // this changes non-leafs into leafs if they have no children.
34162 // it's not very rational behaviour..
34164 if(!this.wasLeaf && this.node.leaf){
34165 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34168 this.wasLeaf = true;
34171 var ecc = "x-tree-ec-icon "+cls;
34172 if(this.ecc != ecc){
34173 this.ecNode.className = ecc;
34179 getChildIndent : function(){
34180 if(!this.childIndent){
34184 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34186 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34188 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34193 this.childIndent = buf.join("");
34195 return this.childIndent;
34198 renderIndent : function(){
34201 var p = this.node.parentNode;
34203 indent = p.ui.getChildIndent();
34205 if(this.indentMarkup != indent){ // don't rerender if not required
34206 this.indentNode.innerHTML = indent;
34207 this.indentMarkup = indent;
34209 this.updateExpandIcon();
34214 Roo.tree.RootTreeNodeUI = function(){
34215 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34217 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34218 render : function(){
34219 if(!this.rendered){
34220 var targetNode = this.node.ownerTree.innerCt.dom;
34221 this.node.expanded = true;
34222 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34223 this.wrap = this.ctNode = targetNode.firstChild;
34226 collapse : function(){
34228 expand : function(){
34232 * Ext JS Library 1.1.1
34233 * Copyright(c) 2006-2007, Ext JS, LLC.
34235 * Originally Released Under LGPL - original licence link has changed is not relivant.
34238 * <script type="text/javascript">
34241 * @class Roo.tree.TreeLoader
34242 * @extends Roo.util.Observable
34243 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34244 * nodes from a specified URL. The response must be a javascript Array definition
34245 * who's elements are node definition objects. eg:
34250 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34251 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34258 * The old style respose with just an array is still supported, but not recommended.
34261 * A server request is sent, and child nodes are loaded only when a node is expanded.
34262 * The loading node's id is passed to the server under the parameter name "node" to
34263 * enable the server to produce the correct child nodes.
34265 * To pass extra parameters, an event handler may be attached to the "beforeload"
34266 * event, and the parameters specified in the TreeLoader's baseParams property:
34268 myTreeLoader.on("beforeload", function(treeLoader, node) {
34269 this.baseParams.category = node.attributes.category;
34272 * This would pass an HTTP parameter called "category" to the server containing
34273 * the value of the Node's "category" attribute.
34275 * Creates a new Treeloader.
34276 * @param {Object} config A config object containing config properties.
34278 Roo.tree.TreeLoader = function(config){
34279 this.baseParams = {};
34280 this.requestMethod = "POST";
34281 Roo.apply(this, config);
34286 * @event beforeload
34287 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34288 * @param {Object} This TreeLoader object.
34289 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34290 * @param {Object} callback The callback function specified in the {@link #load} call.
34295 * Fires when the node has been successfuly loaded.
34296 * @param {Object} This TreeLoader object.
34297 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34298 * @param {Object} response The response object containing the data from the server.
34302 * @event loadexception
34303 * Fires if the network request failed.
34304 * @param {Object} This TreeLoader object.
34305 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34306 * @param {Object} response The response object containing the data from the server.
34308 loadexception : true,
34311 * Fires before a node is created, enabling you to return custom Node types
34312 * @param {Object} This TreeLoader object.
34313 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34318 Roo.tree.TreeLoader.superclass.constructor.call(this);
34321 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34323 * @cfg {String} dataUrl The URL from which to request a Json string which
34324 * specifies an array of node definition object representing the child nodes
34328 * @cfg {String} requestMethod either GET or POST
34329 * defaults to POST (due to BC)
34333 * @cfg {Object} baseParams (optional) An object containing properties which
34334 * specify HTTP parameters to be passed to each request for child nodes.
34337 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34338 * created by this loader. If the attributes sent by the server have an attribute in this object,
34339 * they take priority.
34342 * @cfg {Object} uiProviders (optional) An object containing properties which
34344 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34345 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34346 * <i>uiProvider</i> attribute of a returned child node is a string rather
34347 * than a reference to a TreeNodeUI implementation, this that string value
34348 * is used as a property name in the uiProviders object. You can define the provider named
34349 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34354 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34355 * child nodes before loading.
34357 clearOnLoad : true,
34360 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34361 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34362 * Grid query { data : [ .....] }
34367 * @cfg {String} queryParam (optional)
34368 * Name of the query as it will be passed on the querystring (defaults to 'node')
34369 * eg. the request will be ?node=[id]
34376 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34377 * This is called automatically when a node is expanded, but may be used to reload
34378 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34379 * @param {Roo.tree.TreeNode} node
34380 * @param {Function} callback
34382 load : function(node, callback){
34383 if(this.clearOnLoad){
34384 while(node.firstChild){
34385 node.removeChild(node.firstChild);
34388 if(node.attributes.children){ // preloaded json children
34389 var cs = node.attributes.children;
34390 for(var i = 0, len = cs.length; i < len; i++){
34391 node.appendChild(this.createNode(cs[i]));
34393 if(typeof callback == "function"){
34396 }else if(this.dataUrl){
34397 this.requestData(node, callback);
34401 getParams: function(node){
34402 var buf = [], bp = this.baseParams;
34403 for(var key in bp){
34404 if(typeof bp[key] != "function"){
34405 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34408 var n = this.queryParam === false ? 'node' : this.queryParam;
34409 buf.push(n + "=", encodeURIComponent(node.id));
34410 return buf.join("");
34413 requestData : function(node, callback){
34414 if(this.fireEvent("beforeload", this, node, callback) !== false){
34415 this.transId = Roo.Ajax.request({
34416 method:this.requestMethod,
34417 url: this.dataUrl||this.url,
34418 success: this.handleResponse,
34419 failure: this.handleFailure,
34421 argument: {callback: callback, node: node},
34422 params: this.getParams(node)
34425 // if the load is cancelled, make sure we notify
34426 // the node that we are done
34427 if(typeof callback == "function"){
34433 isLoading : function(){
34434 return this.transId ? true : false;
34437 abort : function(){
34438 if(this.isLoading()){
34439 Roo.Ajax.abort(this.transId);
34444 createNode : function(attr)
34446 // apply baseAttrs, nice idea Corey!
34447 if(this.baseAttrs){
34448 Roo.applyIf(attr, this.baseAttrs);
34450 if(this.applyLoader !== false){
34451 attr.loader = this;
34453 // uiProvider = depreciated..
34455 if(typeof(attr.uiProvider) == 'string'){
34456 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34457 /** eval:var:attr */ eval(attr.uiProvider);
34459 if(typeof(this.uiProviders['default']) != 'undefined') {
34460 attr.uiProvider = this.uiProviders['default'];
34463 this.fireEvent('create', this, attr);
34465 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34467 new Roo.tree.TreeNode(attr) :
34468 new Roo.tree.AsyncTreeNode(attr));
34471 processResponse : function(response, node, callback)
34473 var json = response.responseText;
34476 var o = Roo.decode(json);
34478 if (this.root === false && typeof(o.success) != undefined) {
34479 this.root = 'data'; // the default behaviour for list like data..
34482 if (this.root !== false && !o.success) {
34483 // it's a failure condition.
34484 var a = response.argument;
34485 this.fireEvent("loadexception", this, a.node, response);
34486 Roo.log("Load failed - should have a handler really");
34492 if (this.root !== false) {
34496 for(var i = 0, len = o.length; i < len; i++){
34497 var n = this.createNode(o[i]);
34499 node.appendChild(n);
34502 if(typeof callback == "function"){
34503 callback(this, node);
34506 this.handleFailure(response);
34510 handleResponse : function(response){
34511 this.transId = false;
34512 var a = response.argument;
34513 this.processResponse(response, a.node, a.callback);
34514 this.fireEvent("load", this, a.node, response);
34517 handleFailure : function(response)
34519 // should handle failure better..
34520 this.transId = false;
34521 var a = response.argument;
34522 this.fireEvent("loadexception", this, a.node, response);
34523 if(typeof a.callback == "function"){
34524 a.callback(this, a.node);
34529 * Ext JS Library 1.1.1
34530 * Copyright(c) 2006-2007, Ext JS, LLC.
34532 * Originally Released Under LGPL - original licence link has changed is not relivant.
34535 * <script type="text/javascript">
34539 * @class Roo.tree.TreeFilter
34540 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34541 * @param {TreePanel} tree
34542 * @param {Object} config (optional)
34544 Roo.tree.TreeFilter = function(tree, config){
34546 this.filtered = {};
34547 Roo.apply(this, config);
34550 Roo.tree.TreeFilter.prototype = {
34557 * Filter the data by a specific attribute.
34558 * @param {String/RegExp} value Either string that the attribute value
34559 * should start with or a RegExp to test against the attribute
34560 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34561 * @param {TreeNode} startNode (optional) The node to start the filter at.
34563 filter : function(value, attr, startNode){
34564 attr = attr || "text";
34566 if(typeof value == "string"){
34567 var vlen = value.length;
34568 // auto clear empty filter
34569 if(vlen == 0 && this.clearBlank){
34573 value = value.toLowerCase();
34575 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34577 }else if(value.exec){ // regex?
34579 return value.test(n.attributes[attr]);
34582 throw 'Illegal filter type, must be string or regex';
34584 this.filterBy(f, null, startNode);
34588 * Filter by a function. The passed function will be called with each
34589 * node in the tree (or from the startNode). If the function returns true, the node is kept
34590 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34591 * @param {Function} fn The filter function
34592 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34594 filterBy : function(fn, scope, startNode){
34595 startNode = startNode || this.tree.root;
34596 if(this.autoClear){
34599 var af = this.filtered, rv = this.reverse;
34600 var f = function(n){
34601 if(n == startNode){
34607 var m = fn.call(scope || n, n);
34615 startNode.cascade(f);
34618 if(typeof id != "function"){
34620 if(n && n.parentNode){
34621 n.parentNode.removeChild(n);
34629 * Clears the current filter. Note: with the "remove" option
34630 * set a filter cannot be cleared.
34632 clear : function(){
34634 var af = this.filtered;
34636 if(typeof id != "function"){
34643 this.filtered = {};
34648 * Ext JS Library 1.1.1
34649 * Copyright(c) 2006-2007, Ext JS, LLC.
34651 * Originally Released Under LGPL - original licence link has changed is not relivant.
34654 * <script type="text/javascript">
34659 * @class Roo.tree.TreeSorter
34660 * Provides sorting of nodes in a TreePanel
34662 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34663 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34664 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34665 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34666 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34667 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34669 * @param {TreePanel} tree
34670 * @param {Object} config
34672 Roo.tree.TreeSorter = function(tree, config){
34673 Roo.apply(this, config);
34674 tree.on("beforechildrenrendered", this.doSort, this);
34675 tree.on("append", this.updateSort, this);
34676 tree.on("insert", this.updateSort, this);
34678 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34679 var p = this.property || "text";
34680 var sortType = this.sortType;
34681 var fs = this.folderSort;
34682 var cs = this.caseSensitive === true;
34683 var leafAttr = this.leafAttr || 'leaf';
34685 this.sortFn = function(n1, n2){
34687 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34690 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34694 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34695 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34697 return dsc ? +1 : -1;
34699 return dsc ? -1 : +1;
34706 Roo.tree.TreeSorter.prototype = {
34707 doSort : function(node){
34708 node.sort(this.sortFn);
34711 compareNodes : function(n1, n2){
34712 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34715 updateSort : function(tree, node){
34716 if(node.childrenRendered){
34717 this.doSort.defer(1, this, [node]);
34722 * Ext JS Library 1.1.1
34723 * Copyright(c) 2006-2007, Ext JS, LLC.
34725 * Originally Released Under LGPL - original licence link has changed is not relivant.
34728 * <script type="text/javascript">
34731 if(Roo.dd.DropZone){
34733 Roo.tree.TreeDropZone = function(tree, config){
34734 this.allowParentInsert = false;
34735 this.allowContainerDrop = false;
34736 this.appendOnly = false;
34737 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34739 this.lastInsertClass = "x-tree-no-status";
34740 this.dragOverData = {};
34743 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34744 ddGroup : "TreeDD",
34747 expandDelay : 1000,
34749 expandNode : function(node){
34750 if(node.hasChildNodes() && !node.isExpanded()){
34751 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34755 queueExpand : function(node){
34756 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34759 cancelExpand : function(){
34760 if(this.expandProcId){
34761 clearTimeout(this.expandProcId);
34762 this.expandProcId = false;
34766 isValidDropPoint : function(n, pt, dd, e, data){
34767 if(!n || !data){ return false; }
34768 var targetNode = n.node;
34769 var dropNode = data.node;
34770 // default drop rules
34771 if(!(targetNode && targetNode.isTarget && pt)){
34774 if(pt == "append" && targetNode.allowChildren === false){
34777 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34780 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34783 // reuse the object
34784 var overEvent = this.dragOverData;
34785 overEvent.tree = this.tree;
34786 overEvent.target = targetNode;
34787 overEvent.data = data;
34788 overEvent.point = pt;
34789 overEvent.source = dd;
34790 overEvent.rawEvent = e;
34791 overEvent.dropNode = dropNode;
34792 overEvent.cancel = false;
34793 var result = this.tree.fireEvent("nodedragover", overEvent);
34794 return overEvent.cancel === false && result !== false;
34797 getDropPoint : function(e, n, dd)
34801 return tn.allowChildren !== false ? "append" : false; // always append for root
34803 var dragEl = n.ddel;
34804 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34805 var y = Roo.lib.Event.getPageY(e);
34806 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34808 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34809 var noAppend = tn.allowChildren === false;
34810 if(this.appendOnly || tn.parentNode.allowChildren === false){
34811 return noAppend ? false : "append";
34813 var noBelow = false;
34814 if(!this.allowParentInsert){
34815 noBelow = tn.hasChildNodes() && tn.isExpanded();
34817 var q = (b - t) / (noAppend ? 2 : 3);
34818 if(y >= t && y < (t + q)){
34820 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34827 onNodeEnter : function(n, dd, e, data)
34829 this.cancelExpand();
34832 onNodeOver : function(n, dd, e, data)
34835 var pt = this.getDropPoint(e, n, dd);
34838 // auto node expand check
34839 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34840 this.queueExpand(node);
34841 }else if(pt != "append"){
34842 this.cancelExpand();
34845 // set the insert point style on the target node
34846 var returnCls = this.dropNotAllowed;
34847 if(this.isValidDropPoint(n, pt, dd, e, data)){
34852 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34853 cls = "x-tree-drag-insert-above";
34854 }else if(pt == "below"){
34855 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34856 cls = "x-tree-drag-insert-below";
34858 returnCls = "x-tree-drop-ok-append";
34859 cls = "x-tree-drag-append";
34861 if(this.lastInsertClass != cls){
34862 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34863 this.lastInsertClass = cls;
34870 onNodeOut : function(n, dd, e, data){
34872 this.cancelExpand();
34873 this.removeDropIndicators(n);
34876 onNodeDrop : function(n, dd, e, data){
34877 var point = this.getDropPoint(e, n, dd);
34878 var targetNode = n.node;
34879 targetNode.ui.startDrop();
34880 if(!this.isValidDropPoint(n, point, dd, e, data)){
34881 targetNode.ui.endDrop();
34884 // first try to find the drop node
34885 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34888 target: targetNode,
34893 dropNode: dropNode,
34896 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34897 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34898 targetNode.ui.endDrop();
34901 // allow target changing
34902 targetNode = dropEvent.target;
34903 if(point == "append" && !targetNode.isExpanded()){
34904 targetNode.expand(false, null, function(){
34905 this.completeDrop(dropEvent);
34906 }.createDelegate(this));
34908 this.completeDrop(dropEvent);
34913 completeDrop : function(de){
34914 var ns = de.dropNode, p = de.point, t = de.target;
34915 if(!(ns instanceof Array)){
34919 for(var i = 0, len = ns.length; i < len; i++){
34922 t.parentNode.insertBefore(n, t);
34923 }else if(p == "below"){
34924 t.parentNode.insertBefore(n, t.nextSibling);
34930 if(this.tree.hlDrop){
34934 this.tree.fireEvent("nodedrop", de);
34937 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34938 if(this.tree.hlDrop){
34939 dropNode.ui.focus();
34940 dropNode.ui.highlight();
34942 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34945 getTree : function(){
34949 removeDropIndicators : function(n){
34952 Roo.fly(el).removeClass([
34953 "x-tree-drag-insert-above",
34954 "x-tree-drag-insert-below",
34955 "x-tree-drag-append"]);
34956 this.lastInsertClass = "_noclass";
34960 beforeDragDrop : function(target, e, id){
34961 this.cancelExpand();
34965 afterRepair : function(data){
34966 if(data && Roo.enableFx){
34967 data.node.ui.highlight();
34977 * Ext JS Library 1.1.1
34978 * Copyright(c) 2006-2007, Ext JS, LLC.
34980 * Originally Released Under LGPL - original licence link has changed is not relivant.
34983 * <script type="text/javascript">
34987 if(Roo.dd.DragZone){
34988 Roo.tree.TreeDragZone = function(tree, config){
34989 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34993 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34994 ddGroup : "TreeDD",
34996 onBeforeDrag : function(data, e){
34998 return n && n.draggable && !n.disabled;
35002 onInitDrag : function(e){
35003 var data = this.dragData;
35004 this.tree.getSelectionModel().select(data.node);
35005 this.proxy.update("");
35006 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
35007 this.tree.fireEvent("startdrag", this.tree, data.node, e);
35010 getRepairXY : function(e, data){
35011 return data.node.ui.getDDRepairXY();
35014 onEndDrag : function(data, e){
35015 this.tree.fireEvent("enddrag", this.tree, data.node, e);
35020 onValidDrop : function(dd, e, id){
35021 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
35025 beforeInvalidDrop : function(e, id){
35026 // this scrolls the original position back into view
35027 var sm = this.tree.getSelectionModel();
35028 sm.clearSelections();
35029 sm.select(this.dragData.node);
35034 * Ext JS Library 1.1.1
35035 * Copyright(c) 2006-2007, Ext JS, LLC.
35037 * Originally Released Under LGPL - original licence link has changed is not relivant.
35040 * <script type="text/javascript">
35043 * @class Roo.tree.TreeEditor
35044 * @extends Roo.Editor
35045 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35046 * as the editor field.
35048 * @param {Object} config (used to be the tree panel.)
35049 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35051 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35052 * @cfg {Roo.form.TextField|Object} field The field configuration
35056 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35059 if (oldconfig) { // old style..
35060 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35063 tree = config.tree;
35064 config.field = config.field || {};
35065 config.field.xtype = 'TextField';
35066 field = Roo.factory(config.field, Roo.form);
35068 config = config || {};
35073 * @event beforenodeedit
35074 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35075 * false from the handler of this event.
35076 * @param {Editor} this
35077 * @param {Roo.tree.Node} node
35079 "beforenodeedit" : true
35083 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35087 tree.on('beforeclick', this.beforeNodeClick, this);
35088 tree.getTreeEl().on('mousedown', this.hide, this);
35089 this.on('complete', this.updateNode, this);
35090 this.on('beforestartedit', this.fitToTree, this);
35091 this.on('startedit', this.bindScroll, this, {delay:10});
35092 this.on('specialkey', this.onSpecialKey, this);
35095 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35097 * @cfg {String} alignment
35098 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35104 * @cfg {Boolean} hideEl
35105 * True to hide the bound element while the editor is displayed (defaults to false)
35109 * @cfg {String} cls
35110 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35112 cls: "x-small-editor x-tree-editor",
35114 * @cfg {Boolean} shim
35115 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35121 * @cfg {Number} maxWidth
35122 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35123 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35124 * scroll and client offsets into account prior to each edit.
35131 fitToTree : function(ed, el){
35132 var td = this.tree.getTreeEl().dom, nd = el.dom;
35133 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35134 td.scrollLeft = nd.offsetLeft;
35138 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35139 this.setSize(w, '');
35141 return this.fireEvent('beforenodeedit', this, this.editNode);
35146 triggerEdit : function(node){
35147 this.completeEdit();
35148 this.editNode = node;
35149 this.startEdit(node.ui.textNode, node.text);
35153 bindScroll : function(){
35154 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35158 beforeNodeClick : function(node, e){
35159 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35160 this.lastClick = new Date();
35161 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35163 this.triggerEdit(node);
35170 updateNode : function(ed, value){
35171 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35172 this.editNode.setText(value);
35176 onHide : function(){
35177 Roo.tree.TreeEditor.superclass.onHide.call(this);
35179 this.editNode.ui.focus();
35184 onSpecialKey : function(field, e){
35185 var k = e.getKey();
35189 }else if(k == e.ENTER && !e.hasModifier()){
35191 this.completeEdit();
35194 });//<Script type="text/javascript">
35197 * Ext JS Library 1.1.1
35198 * Copyright(c) 2006-2007, Ext JS, LLC.
35200 * Originally Released Under LGPL - original licence link has changed is not relivant.
35203 * <script type="text/javascript">
35207 * Not documented??? - probably should be...
35210 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35211 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35213 renderElements : function(n, a, targetNode, bulkRender){
35214 //consel.log("renderElements?");
35215 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35217 var t = n.getOwnerTree();
35218 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35220 var cols = t.columns;
35221 var bw = t.borderWidth;
35223 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35224 var cb = typeof a.checked == "boolean";
35225 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35226 var colcls = 'x-t-' + tid + '-c0';
35228 '<li class="x-tree-node">',
35231 '<div class="x-tree-node-el ', a.cls,'">',
35233 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35236 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35237 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35238 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35239 (a.icon ? ' x-tree-node-inline-icon' : ''),
35240 (a.iconCls ? ' '+a.iconCls : ''),
35241 '" unselectable="on" />',
35242 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35243 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35245 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35246 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35247 '<span unselectable="on" qtip="' + tx + '">',
35251 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35252 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35254 for(var i = 1, len = cols.length; i < len; i++){
35256 colcls = 'x-t-' + tid + '-c' +i;
35257 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35258 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35259 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35265 '<div class="x-clear"></div></div>',
35266 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35269 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35270 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35271 n.nextSibling.ui.getEl(), buf.join(""));
35273 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35275 var el = this.wrap.firstChild;
35277 this.elNode = el.firstChild;
35278 this.ranchor = el.childNodes[1];
35279 this.ctNode = this.wrap.childNodes[1];
35280 var cs = el.firstChild.childNodes;
35281 this.indentNode = cs[0];
35282 this.ecNode = cs[1];
35283 this.iconNode = cs[2];
35286 this.checkbox = cs[3];
35289 this.anchor = cs[index];
35291 this.textNode = cs[index].firstChild;
35293 //el.on("click", this.onClick, this);
35294 //el.on("dblclick", this.onDblClick, this);
35297 // console.log(this);
35299 initEvents : function(){
35300 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35303 var a = this.ranchor;
35305 var el = Roo.get(a);
35307 if(Roo.isOpera){ // opera render bug ignores the CSS
35308 el.setStyle("text-decoration", "none");
35311 el.on("click", this.onClick, this);
35312 el.on("dblclick", this.onDblClick, this);
35313 el.on("contextmenu", this.onContextMenu, this);
35317 /*onSelectedChange : function(state){
35320 this.addClass("x-tree-selected");
35323 this.removeClass("x-tree-selected");
35326 addClass : function(cls){
35328 Roo.fly(this.elRow).addClass(cls);
35334 removeClass : function(cls){
35336 Roo.fly(this.elRow).removeClass(cls);
35342 });//<Script type="text/javascript">
35346 * Ext JS Library 1.1.1
35347 * Copyright(c) 2006-2007, Ext JS, LLC.
35349 * Originally Released Under LGPL - original licence link has changed is not relivant.
35352 * <script type="text/javascript">
35357 * @class Roo.tree.ColumnTree
35358 * @extends Roo.data.TreePanel
35359 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35360 * @cfg {int} borderWidth compined right/left border allowance
35362 * @param {String/HTMLElement/Element} el The container element
35363 * @param {Object} config
35365 Roo.tree.ColumnTree = function(el, config)
35367 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35371 * Fire this event on a container when it resizes
35372 * @param {int} w Width
35373 * @param {int} h Height
35377 this.on('resize', this.onResize, this);
35380 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35384 borderWidth: Roo.isBorderBox ? 0 : 2,
35387 render : function(){
35388 // add the header.....
35390 Roo.tree.ColumnTree.superclass.render.apply(this);
35392 this.el.addClass('x-column-tree');
35394 this.headers = this.el.createChild(
35395 {cls:'x-tree-headers'},this.innerCt.dom);
35397 var cols = this.columns, c;
35398 var totalWidth = 0;
35400 var len = cols.length;
35401 for(var i = 0; i < len; i++){
35403 totalWidth += c.width;
35404 this.headEls.push(this.headers.createChild({
35405 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35407 cls:'x-tree-hd-text',
35410 style:'width:'+(c.width-this.borderWidth)+'px;'
35413 this.headers.createChild({cls:'x-clear'});
35414 // prevent floats from wrapping when clipped
35415 this.headers.setWidth(totalWidth);
35416 //this.innerCt.setWidth(totalWidth);
35417 this.innerCt.setStyle({ overflow: 'auto' });
35418 this.onResize(this.width, this.height);
35422 onResize : function(w,h)
35427 this.innerCt.setWidth(this.width);
35428 this.innerCt.setHeight(this.height-20);
35431 var cols = this.columns, c;
35432 var totalWidth = 0;
35434 var len = cols.length;
35435 for(var i = 0; i < len; i++){
35437 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35438 // it's the expander..
35439 expEl = this.headEls[i];
35442 totalWidth += c.width;
35446 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35448 this.headers.setWidth(w-20);
35457 * Ext JS Library 1.1.1
35458 * Copyright(c) 2006-2007, Ext JS, LLC.
35460 * Originally Released Under LGPL - original licence link has changed is not relivant.
35463 * <script type="text/javascript">
35467 * @class Roo.menu.Menu
35468 * @extends Roo.util.Observable
35469 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35470 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35472 * Creates a new Menu
35473 * @param {Object} config Configuration options
35475 Roo.menu.Menu = function(config){
35476 Roo.apply(this, config);
35477 this.id = this.id || Roo.id();
35480 * @event beforeshow
35481 * Fires before this menu is displayed
35482 * @param {Roo.menu.Menu} this
35486 * @event beforehide
35487 * Fires before this menu is hidden
35488 * @param {Roo.menu.Menu} this
35493 * Fires after this menu is displayed
35494 * @param {Roo.menu.Menu} this
35499 * Fires after this menu is hidden
35500 * @param {Roo.menu.Menu} this
35505 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35506 * @param {Roo.menu.Menu} this
35507 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35508 * @param {Roo.EventObject} e
35513 * Fires when the mouse is hovering over this menu
35514 * @param {Roo.menu.Menu} this
35515 * @param {Roo.EventObject} e
35516 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35521 * Fires when the mouse exits this menu
35522 * @param {Roo.menu.Menu} this
35523 * @param {Roo.EventObject} e
35524 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35529 * Fires when a menu item contained in this menu is clicked
35530 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35531 * @param {Roo.EventObject} e
35535 if (this.registerMenu) {
35536 Roo.menu.MenuMgr.register(this);
35539 var mis = this.items;
35540 this.items = new Roo.util.MixedCollection();
35542 this.add.apply(this, mis);
35546 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35548 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35552 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35553 * for bottom-right shadow (defaults to "sides")
35557 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35558 * this menu (defaults to "tl-tr?")
35560 subMenuAlign : "tl-tr?",
35562 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35563 * relative to its element of origin (defaults to "tl-bl?")
35565 defaultAlign : "tl-bl?",
35567 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35569 allowOtherMenus : false,
35571 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35573 registerMenu : true,
35578 render : function(){
35582 var el = this.el = new Roo.Layer({
35584 shadow:this.shadow,
35586 parentEl: this.parentEl || document.body,
35590 this.keyNav = new Roo.menu.MenuNav(this);
35593 el.addClass("x-menu-plain");
35596 el.addClass(this.cls);
35598 // generic focus element
35599 this.focusEl = el.createChild({
35600 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35602 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35603 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35605 ul.on("mouseover", this.onMouseOver, this);
35606 ul.on("mouseout", this.onMouseOut, this);
35607 this.items.each(function(item){
35612 var li = document.createElement("li");
35613 li.className = "x-menu-list-item";
35614 ul.dom.appendChild(li);
35615 item.render(li, this);
35622 autoWidth : function(){
35623 var el = this.el, ul = this.ul;
35627 var w = this.width;
35630 }else if(Roo.isIE){
35631 el.setWidth(this.minWidth);
35632 var t = el.dom.offsetWidth; // force recalc
35633 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35638 delayAutoWidth : function(){
35641 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35643 this.awTask.delay(20);
35648 findTargetItem : function(e){
35649 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35650 if(t && t.menuItemId){
35651 return this.items.get(t.menuItemId);
35656 onClick : function(e){
35657 Roo.log("menu.onClick");
35658 var t = this.findTargetItem(e);
35663 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35664 if(t == this.activeItem && t.shouldDeactivate(e)){
35665 this.activeItem.deactivate();
35666 delete this.activeItem;
35670 this.setActiveItem(t, true);
35678 this.fireEvent("click", this, t, e);
35682 setActiveItem : function(item, autoExpand){
35683 if(item != this.activeItem){
35684 if(this.activeItem){
35685 this.activeItem.deactivate();
35687 this.activeItem = item;
35688 item.activate(autoExpand);
35689 }else if(autoExpand){
35695 tryActivate : function(start, step){
35696 var items = this.items;
35697 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35698 var item = items.get(i);
35699 if(!item.disabled && item.canActivate){
35700 this.setActiveItem(item, false);
35708 onMouseOver : function(e){
35710 if(t = this.findTargetItem(e)){
35711 if(t.canActivate && !t.disabled){
35712 this.setActiveItem(t, true);
35715 this.fireEvent("mouseover", this, e, t);
35719 onMouseOut : function(e){
35721 if(t = this.findTargetItem(e)){
35722 if(t == this.activeItem && t.shouldDeactivate(e)){
35723 this.activeItem.deactivate();
35724 delete this.activeItem;
35727 this.fireEvent("mouseout", this, e, t);
35731 * Read-only. Returns true if the menu is currently displayed, else false.
35734 isVisible : function(){
35735 return this.el && !this.hidden;
35739 * Displays this menu relative to another element
35740 * @param {String/HTMLElement/Roo.Element} element The element to align to
35741 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35742 * the element (defaults to this.defaultAlign)
35743 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35745 show : function(el, pos, parentMenu){
35746 this.parentMenu = parentMenu;
35750 this.fireEvent("beforeshow", this);
35751 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35755 * Displays this menu at a specific xy position
35756 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35757 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35759 showAt : function(xy, parentMenu, /* private: */_e){
35760 this.parentMenu = parentMenu;
35765 this.fireEvent("beforeshow", this);
35766 xy = this.el.adjustForConstraints(xy);
35770 this.hidden = false;
35772 this.fireEvent("show", this);
35775 focus : function(){
35777 this.doFocus.defer(50, this);
35781 doFocus : function(){
35783 this.focusEl.focus();
35788 * Hides this menu and optionally all parent menus
35789 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35791 hide : function(deep){
35792 if(this.el && this.isVisible()){
35793 this.fireEvent("beforehide", this);
35794 if(this.activeItem){
35795 this.activeItem.deactivate();
35796 this.activeItem = null;
35799 this.hidden = true;
35800 this.fireEvent("hide", this);
35802 if(deep === true && this.parentMenu){
35803 this.parentMenu.hide(true);
35808 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35809 * Any of the following are valid:
35811 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35812 * <li>An HTMLElement object which will be converted to a menu item</li>
35813 * <li>A menu item config object that will be created as a new menu item</li>
35814 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35815 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35820 var menu = new Roo.menu.Menu();
35822 // Create a menu item to add by reference
35823 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35825 // Add a bunch of items at once using different methods.
35826 // Only the last item added will be returned.
35827 var item = menu.add(
35828 menuItem, // add existing item by ref
35829 'Dynamic Item', // new TextItem
35830 '-', // new separator
35831 { text: 'Config Item' } // new item by config
35834 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35835 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35838 var a = arguments, l = a.length, item;
35839 for(var i = 0; i < l; i++){
35841 if ((typeof(el) == "object") && el.xtype && el.xns) {
35842 el = Roo.factory(el, Roo.menu);
35845 if(el.render){ // some kind of Item
35846 item = this.addItem(el);
35847 }else if(typeof el == "string"){ // string
35848 if(el == "separator" || el == "-"){
35849 item = this.addSeparator();
35851 item = this.addText(el);
35853 }else if(el.tagName || el.el){ // element
35854 item = this.addElement(el);
35855 }else if(typeof el == "object"){ // must be menu item config?
35856 item = this.addMenuItem(el);
35863 * Returns this menu's underlying {@link Roo.Element} object
35864 * @return {Roo.Element} The element
35866 getEl : function(){
35874 * Adds a separator bar to the menu
35875 * @return {Roo.menu.Item} The menu item that was added
35877 addSeparator : function(){
35878 return this.addItem(new Roo.menu.Separator());
35882 * Adds an {@link Roo.Element} object to the menu
35883 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35884 * @return {Roo.menu.Item} The menu item that was added
35886 addElement : function(el){
35887 return this.addItem(new Roo.menu.BaseItem(el));
35891 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35892 * @param {Roo.menu.Item} item The menu item to add
35893 * @return {Roo.menu.Item} The menu item that was added
35895 addItem : function(item){
35896 this.items.add(item);
35898 var li = document.createElement("li");
35899 li.className = "x-menu-list-item";
35900 this.ul.dom.appendChild(li);
35901 item.render(li, this);
35902 this.delayAutoWidth();
35908 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35909 * @param {Object} config A MenuItem config object
35910 * @return {Roo.menu.Item} The menu item that was added
35912 addMenuItem : function(config){
35913 if(!(config instanceof Roo.menu.Item)){
35914 if(typeof config.checked == "boolean"){ // must be check menu item config?
35915 config = new Roo.menu.CheckItem(config);
35917 config = new Roo.menu.Item(config);
35920 return this.addItem(config);
35924 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35925 * @param {String} text The text to display in the menu item
35926 * @return {Roo.menu.Item} The menu item that was added
35928 addText : function(text){
35929 return this.addItem(new Roo.menu.TextItem({ text : text }));
35933 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35934 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35935 * @param {Roo.menu.Item} item The menu item to add
35936 * @return {Roo.menu.Item} The menu item that was added
35938 insert : function(index, item){
35939 this.items.insert(index, item);
35941 var li = document.createElement("li");
35942 li.className = "x-menu-list-item";
35943 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35944 item.render(li, this);
35945 this.delayAutoWidth();
35951 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35952 * @param {Roo.menu.Item} item The menu item to remove
35954 remove : function(item){
35955 this.items.removeKey(item.id);
35960 * Removes and destroys all items in the menu
35962 removeAll : function(){
35964 while(f = this.items.first()){
35970 // MenuNav is a private utility class used internally by the Menu
35971 Roo.menu.MenuNav = function(menu){
35972 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35973 this.scope = this.menu = menu;
35976 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35977 doRelay : function(e, h){
35978 var k = e.getKey();
35979 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35980 this.menu.tryActivate(0, 1);
35983 return h.call(this.scope || this, e, this.menu);
35986 up : function(e, m){
35987 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35988 m.tryActivate(m.items.length-1, -1);
35992 down : function(e, m){
35993 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35994 m.tryActivate(0, 1);
35998 right : function(e, m){
36000 m.activeItem.expandMenu(true);
36004 left : function(e, m){
36006 if(m.parentMenu && m.parentMenu.activeItem){
36007 m.parentMenu.activeItem.activate();
36011 enter : function(e, m){
36013 e.stopPropagation();
36014 m.activeItem.onClick(e);
36015 m.fireEvent("click", this, m.activeItem);
36021 * Ext JS Library 1.1.1
36022 * Copyright(c) 2006-2007, Ext JS, LLC.
36024 * Originally Released Under LGPL - original licence link has changed is not relivant.
36027 * <script type="text/javascript">
36031 * @class Roo.menu.MenuMgr
36032 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
36035 Roo.menu.MenuMgr = function(){
36036 var menus, active, groups = {}, attached = false, lastShow = new Date();
36038 // private - called when first menu is created
36041 active = new Roo.util.MixedCollection();
36042 Roo.get(document).addKeyListener(27, function(){
36043 if(active.length > 0){
36050 function hideAll(){
36051 if(active && active.length > 0){
36052 var c = active.clone();
36053 c.each(function(m){
36060 function onHide(m){
36062 if(active.length < 1){
36063 Roo.get(document).un("mousedown", onMouseDown);
36069 function onShow(m){
36070 var last = active.last();
36071 lastShow = new Date();
36074 Roo.get(document).on("mousedown", onMouseDown);
36078 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36079 m.parentMenu.activeChild = m;
36080 }else if(last && last.isVisible()){
36081 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36086 function onBeforeHide(m){
36088 m.activeChild.hide();
36090 if(m.autoHideTimer){
36091 clearTimeout(m.autoHideTimer);
36092 delete m.autoHideTimer;
36097 function onBeforeShow(m){
36098 var pm = m.parentMenu;
36099 if(!pm && !m.allowOtherMenus){
36101 }else if(pm && pm.activeChild && active != m){
36102 pm.activeChild.hide();
36107 function onMouseDown(e){
36108 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36114 function onBeforeCheck(mi, state){
36116 var g = groups[mi.group];
36117 for(var i = 0, l = g.length; i < l; i++){
36119 g[i].setChecked(false);
36128 * Hides all menus that are currently visible
36130 hideAll : function(){
36135 register : function(menu){
36139 menus[menu.id] = menu;
36140 menu.on("beforehide", onBeforeHide);
36141 menu.on("hide", onHide);
36142 menu.on("beforeshow", onBeforeShow);
36143 menu.on("show", onShow);
36144 var g = menu.group;
36145 if(g && menu.events["checkchange"]){
36149 groups[g].push(menu);
36150 menu.on("checkchange", onCheck);
36155 * Returns a {@link Roo.menu.Menu} object
36156 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36157 * be used to generate and return a new Menu instance.
36159 get : function(menu){
36160 if(typeof menu == "string"){ // menu id
36161 return menus[menu];
36162 }else if(menu.events){ // menu instance
36164 }else if(typeof menu.length == 'number'){ // array of menu items?
36165 return new Roo.menu.Menu({items:menu});
36166 }else{ // otherwise, must be a config
36167 return new Roo.menu.Menu(menu);
36172 unregister : function(menu){
36173 delete menus[menu.id];
36174 menu.un("beforehide", onBeforeHide);
36175 menu.un("hide", onHide);
36176 menu.un("beforeshow", onBeforeShow);
36177 menu.un("show", onShow);
36178 var g = menu.group;
36179 if(g && menu.events["checkchange"]){
36180 groups[g].remove(menu);
36181 menu.un("checkchange", onCheck);
36186 registerCheckable : function(menuItem){
36187 var g = menuItem.group;
36192 groups[g].push(menuItem);
36193 menuItem.on("beforecheckchange", onBeforeCheck);
36198 unregisterCheckable : function(menuItem){
36199 var g = menuItem.group;
36201 groups[g].remove(menuItem);
36202 menuItem.un("beforecheckchange", onBeforeCheck);
36208 * Ext JS Library 1.1.1
36209 * Copyright(c) 2006-2007, Ext JS, LLC.
36211 * Originally Released Under LGPL - original licence link has changed is not relivant.
36214 * <script type="text/javascript">
36219 * @class Roo.menu.BaseItem
36220 * @extends Roo.Component
36221 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36222 * management and base configuration options shared by all menu components.
36224 * Creates a new BaseItem
36225 * @param {Object} config Configuration options
36227 Roo.menu.BaseItem = function(config){
36228 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36233 * Fires when this item is clicked
36234 * @param {Roo.menu.BaseItem} this
36235 * @param {Roo.EventObject} e
36240 * Fires when this item is activated
36241 * @param {Roo.menu.BaseItem} this
36245 * @event deactivate
36246 * Fires when this item is deactivated
36247 * @param {Roo.menu.BaseItem} this
36253 this.on("click", this.handler, this.scope, true);
36257 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36259 * @cfg {Function} handler
36260 * A function that will handle the click event of this menu item (defaults to undefined)
36263 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36265 canActivate : false,
36268 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36273 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36275 activeClass : "x-menu-item-active",
36277 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36279 hideOnClick : true,
36281 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36286 ctype: "Roo.menu.BaseItem",
36289 actionMode : "container",
36292 render : function(container, parentMenu){
36293 this.parentMenu = parentMenu;
36294 Roo.menu.BaseItem.superclass.render.call(this, container);
36295 this.container.menuItemId = this.id;
36299 onRender : function(container, position){
36300 this.el = Roo.get(this.el);
36301 container.dom.appendChild(this.el.dom);
36305 onClick : function(e){
36306 if(!this.disabled && this.fireEvent("click", this, e) !== false
36307 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36308 this.handleClick(e);
36315 activate : function(){
36319 var li = this.container;
36320 li.addClass(this.activeClass);
36321 this.region = li.getRegion().adjust(2, 2, -2, -2);
36322 this.fireEvent("activate", this);
36327 deactivate : function(){
36328 this.container.removeClass(this.activeClass);
36329 this.fireEvent("deactivate", this);
36333 shouldDeactivate : function(e){
36334 return !this.region || !this.region.contains(e.getPoint());
36338 handleClick : function(e){
36339 if(this.hideOnClick){
36340 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36345 expandMenu : function(autoActivate){
36350 hideMenu : function(){
36355 * Ext JS Library 1.1.1
36356 * Copyright(c) 2006-2007, Ext JS, LLC.
36358 * Originally Released Under LGPL - original licence link has changed is not relivant.
36361 * <script type="text/javascript">
36365 * @class Roo.menu.Adapter
36366 * @extends Roo.menu.BaseItem
36367 * 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.
36368 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36370 * Creates a new Adapter
36371 * @param {Object} config Configuration options
36373 Roo.menu.Adapter = function(component, config){
36374 Roo.menu.Adapter.superclass.constructor.call(this, config);
36375 this.component = component;
36377 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36379 canActivate : true,
36382 onRender : function(container, position){
36383 this.component.render(container);
36384 this.el = this.component.getEl();
36388 activate : function(){
36392 this.component.focus();
36393 this.fireEvent("activate", this);
36398 deactivate : function(){
36399 this.fireEvent("deactivate", this);
36403 disable : function(){
36404 this.component.disable();
36405 Roo.menu.Adapter.superclass.disable.call(this);
36409 enable : function(){
36410 this.component.enable();
36411 Roo.menu.Adapter.superclass.enable.call(this);
36415 * Ext JS Library 1.1.1
36416 * Copyright(c) 2006-2007, Ext JS, LLC.
36418 * Originally Released Under LGPL - original licence link has changed is not relivant.
36421 * <script type="text/javascript">
36425 * @class Roo.menu.TextItem
36426 * @extends Roo.menu.BaseItem
36427 * Adds a static text string to a menu, usually used as either a heading or group separator.
36428 * Note: old style constructor with text is still supported.
36431 * Creates a new TextItem
36432 * @param {Object} cfg Configuration
36434 Roo.menu.TextItem = function(cfg){
36435 if (typeof(cfg) == 'string') {
36438 Roo.apply(this,cfg);
36441 Roo.menu.TextItem.superclass.constructor.call(this);
36444 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36446 * @cfg {Boolean} text Text to show on item.
36451 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36453 hideOnClick : false,
36455 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36457 itemCls : "x-menu-text",
36460 onRender : function(){
36461 var s = document.createElement("span");
36462 s.className = this.itemCls;
36463 s.innerHTML = this.text;
36465 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36469 * Ext JS Library 1.1.1
36470 * Copyright(c) 2006-2007, Ext JS, LLC.
36472 * Originally Released Under LGPL - original licence link has changed is not relivant.
36475 * <script type="text/javascript">
36479 * @class Roo.menu.Separator
36480 * @extends Roo.menu.BaseItem
36481 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36482 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36484 * @param {Object} config Configuration options
36486 Roo.menu.Separator = function(config){
36487 Roo.menu.Separator.superclass.constructor.call(this, config);
36490 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36492 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36494 itemCls : "x-menu-sep",
36496 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36498 hideOnClick : false,
36501 onRender : function(li){
36502 var s = document.createElement("span");
36503 s.className = this.itemCls;
36504 s.innerHTML = " ";
36506 li.addClass("x-menu-sep-li");
36507 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36511 * Ext JS Library 1.1.1
36512 * Copyright(c) 2006-2007, Ext JS, LLC.
36514 * Originally Released Under LGPL - original licence link has changed is not relivant.
36517 * <script type="text/javascript">
36520 * @class Roo.menu.Item
36521 * @extends Roo.menu.BaseItem
36522 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36523 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36524 * activation and click handling.
36526 * Creates a new Item
36527 * @param {Object} config Configuration options
36529 Roo.menu.Item = function(config){
36530 Roo.menu.Item.superclass.constructor.call(this, config);
36532 this.menu = Roo.menu.MenuMgr.get(this.menu);
36535 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36538 * @cfg {String} text
36539 * The text to show on the menu item.
36543 * @cfg {String} HTML to render in menu
36544 * The text to show on the menu item (HTML version).
36548 * @cfg {String} icon
36549 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36553 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36555 itemCls : "x-menu-item",
36557 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36559 canActivate : true,
36561 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36564 // doc'd in BaseItem
36568 ctype: "Roo.menu.Item",
36571 onRender : function(container, position){
36572 var el = document.createElement("a");
36573 el.hideFocus = true;
36574 el.unselectable = "on";
36575 el.href = this.href || "#";
36576 if(this.hrefTarget){
36577 el.target = this.hrefTarget;
36579 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36581 var html = this.html.length ? this.html : String.format('{0}',this.text);
36583 el.innerHTML = String.format(
36584 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36585 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36587 Roo.menu.Item.superclass.onRender.call(this, container, position);
36591 * Sets the text to display in this menu item
36592 * @param {String} text The text to display
36593 * @param {Boolean} isHTML true to indicate text is pure html.
36595 setText : function(text, isHTML){
36603 var html = this.html.length ? this.html : String.format('{0}',this.text);
36605 this.el.update(String.format(
36606 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36607 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36608 this.parentMenu.autoWidth();
36613 handleClick : function(e){
36614 if(!this.href){ // if no link defined, stop the event automatically
36617 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36621 activate : function(autoExpand){
36622 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36632 shouldDeactivate : function(e){
36633 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36634 if(this.menu && this.menu.isVisible()){
36635 return !this.menu.getEl().getRegion().contains(e.getPoint());
36643 deactivate : function(){
36644 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36649 expandMenu : function(autoActivate){
36650 if(!this.disabled && this.menu){
36651 clearTimeout(this.hideTimer);
36652 delete this.hideTimer;
36653 if(!this.menu.isVisible() && !this.showTimer){
36654 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36655 }else if (this.menu.isVisible() && autoActivate){
36656 this.menu.tryActivate(0, 1);
36662 deferExpand : function(autoActivate){
36663 delete this.showTimer;
36664 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36666 this.menu.tryActivate(0, 1);
36671 hideMenu : function(){
36672 clearTimeout(this.showTimer);
36673 delete this.showTimer;
36674 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36675 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36680 deferHide : function(){
36681 delete this.hideTimer;
36686 * Ext JS Library 1.1.1
36687 * Copyright(c) 2006-2007, Ext JS, LLC.
36689 * Originally Released Under LGPL - original licence link has changed is not relivant.
36692 * <script type="text/javascript">
36696 * @class Roo.menu.CheckItem
36697 * @extends Roo.menu.Item
36698 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36700 * Creates a new CheckItem
36701 * @param {Object} config Configuration options
36703 Roo.menu.CheckItem = function(config){
36704 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36707 * @event beforecheckchange
36708 * Fires before the checked value is set, providing an opportunity to cancel if needed
36709 * @param {Roo.menu.CheckItem} this
36710 * @param {Boolean} checked The new checked value that will be set
36712 "beforecheckchange" : true,
36714 * @event checkchange
36715 * Fires after the checked value has been set
36716 * @param {Roo.menu.CheckItem} this
36717 * @param {Boolean} checked The checked value that was set
36719 "checkchange" : true
36721 if(this.checkHandler){
36722 this.on('checkchange', this.checkHandler, this.scope);
36725 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36727 * @cfg {String} group
36728 * All check items with the same group name will automatically be grouped into a single-select
36729 * radio button group (defaults to '')
36732 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36734 itemCls : "x-menu-item x-menu-check-item",
36736 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36738 groupClass : "x-menu-group-item",
36741 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36742 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36743 * initialized with checked = true will be rendered as checked.
36748 ctype: "Roo.menu.CheckItem",
36751 onRender : function(c){
36752 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36754 this.el.addClass(this.groupClass);
36756 Roo.menu.MenuMgr.registerCheckable(this);
36758 this.checked = false;
36759 this.setChecked(true, true);
36764 destroy : function(){
36766 Roo.menu.MenuMgr.unregisterCheckable(this);
36768 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36772 * Set the checked state of this item
36773 * @param {Boolean} checked The new checked value
36774 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36776 setChecked : function(state, suppressEvent){
36777 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36778 if(this.container){
36779 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36781 this.checked = state;
36782 if(suppressEvent !== true){
36783 this.fireEvent("checkchange", this, state);
36789 handleClick : function(e){
36790 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36791 this.setChecked(!this.checked);
36793 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36797 * Ext JS Library 1.1.1
36798 * Copyright(c) 2006-2007, Ext JS, LLC.
36800 * Originally Released Under LGPL - original licence link has changed is not relivant.
36803 * <script type="text/javascript">
36807 * @class Roo.menu.DateItem
36808 * @extends Roo.menu.Adapter
36809 * A menu item that wraps the {@link Roo.DatPicker} component.
36811 * Creates a new DateItem
36812 * @param {Object} config Configuration options
36814 Roo.menu.DateItem = function(config){
36815 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36816 /** The Roo.DatePicker object @type Roo.DatePicker */
36817 this.picker = this.component;
36818 this.addEvents({select: true});
36820 this.picker.on("render", function(picker){
36821 picker.getEl().swallowEvent("click");
36822 picker.container.addClass("x-menu-date-item");
36825 this.picker.on("select", this.onSelect, this);
36828 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36830 onSelect : function(picker, date){
36831 this.fireEvent("select", this, date, picker);
36832 Roo.menu.DateItem.superclass.handleClick.call(this);
36836 * Ext JS Library 1.1.1
36837 * Copyright(c) 2006-2007, Ext JS, LLC.
36839 * Originally Released Under LGPL - original licence link has changed is not relivant.
36842 * <script type="text/javascript">
36846 * @class Roo.menu.ColorItem
36847 * @extends Roo.menu.Adapter
36848 * A menu item that wraps the {@link Roo.ColorPalette} component.
36850 * Creates a new ColorItem
36851 * @param {Object} config Configuration options
36853 Roo.menu.ColorItem = function(config){
36854 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36855 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36856 this.palette = this.component;
36857 this.relayEvents(this.palette, ["select"]);
36858 if(this.selectHandler){
36859 this.on('select', this.selectHandler, this.scope);
36862 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36864 * Ext JS Library 1.1.1
36865 * Copyright(c) 2006-2007, Ext JS, LLC.
36867 * Originally Released Under LGPL - original licence link has changed is not relivant.
36870 * <script type="text/javascript">
36875 * @class Roo.menu.DateMenu
36876 * @extends Roo.menu.Menu
36877 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36879 * Creates a new DateMenu
36880 * @param {Object} config Configuration options
36882 Roo.menu.DateMenu = function(config){
36883 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36885 var di = new Roo.menu.DateItem(config);
36888 * The {@link Roo.DatePicker} instance for this DateMenu
36891 this.picker = di.picker;
36894 * @param {DatePicker} picker
36895 * @param {Date} date
36897 this.relayEvents(di, ["select"]);
36898 this.on('beforeshow', function(){
36900 this.picker.hideMonthPicker(false);
36904 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36908 * Ext JS Library 1.1.1
36909 * Copyright(c) 2006-2007, Ext JS, LLC.
36911 * Originally Released Under LGPL - original licence link has changed is not relivant.
36914 * <script type="text/javascript">
36919 * @class Roo.menu.ColorMenu
36920 * @extends Roo.menu.Menu
36921 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36923 * Creates a new ColorMenu
36924 * @param {Object} config Configuration options
36926 Roo.menu.ColorMenu = function(config){
36927 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36929 var ci = new Roo.menu.ColorItem(config);
36932 * The {@link Roo.ColorPalette} instance for this ColorMenu
36933 * @type ColorPalette
36935 this.palette = ci.palette;
36938 * @param {ColorPalette} palette
36939 * @param {String} color
36941 this.relayEvents(ci, ["select"]);
36943 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36945 * Ext JS Library 1.1.1
36946 * Copyright(c) 2006-2007, Ext JS, LLC.
36948 * Originally Released Under LGPL - original licence link has changed is not relivant.
36951 * <script type="text/javascript">
36955 * @class Roo.form.Field
36956 * @extends Roo.BoxComponent
36957 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36959 * Creates a new Field
36960 * @param {Object} config Configuration options
36962 Roo.form.Field = function(config){
36963 Roo.form.Field.superclass.constructor.call(this, config);
36966 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36968 * @cfg {String} fieldLabel Label to use when rendering a form.
36971 * @cfg {String} qtip Mouse over tip
36975 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36977 invalidClass : "x-form-invalid",
36979 * @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")
36981 invalidText : "The value in this field is invalid",
36983 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36985 focusClass : "x-form-focus",
36987 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36988 automatic validation (defaults to "keyup").
36990 validationEvent : "keyup",
36992 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36994 validateOnBlur : true,
36996 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36998 validationDelay : 250,
37000 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37001 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
37003 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
37005 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
37007 fieldClass : "x-form-field",
37009 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
37012 ----------- ----------------------------------------------------------------------
37013 qtip Display a quick tip when the user hovers over the field
37014 title Display a default browser title attribute popup
37015 under Add a block div beneath the field containing the error text
37016 side Add an error icon to the right of the field with a popup on hover
37017 [element id] Add the error text directly to the innerHTML of the specified element
37020 msgTarget : 'qtip',
37022 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
37027 * @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.
37032 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37037 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37039 inputType : undefined,
37042 * @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).
37044 tabIndex : undefined,
37047 isFormField : true,
37052 * @property {Roo.Element} fieldEl
37053 * Element Containing the rendered Field (with label etc.)
37056 * @cfg {Mixed} value A value to initialize this field with.
37061 * @cfg {String} name The field's HTML name attribute.
37064 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37068 initComponent : function(){
37069 Roo.form.Field.superclass.initComponent.call(this);
37073 * Fires when this field receives input focus.
37074 * @param {Roo.form.Field} this
37079 * Fires when this field loses input focus.
37080 * @param {Roo.form.Field} this
37084 * @event specialkey
37085 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37086 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37087 * @param {Roo.form.Field} this
37088 * @param {Roo.EventObject} e The event object
37093 * Fires just before the field blurs if the field value has changed.
37094 * @param {Roo.form.Field} this
37095 * @param {Mixed} newValue The new value
37096 * @param {Mixed} oldValue The original value
37101 * Fires after the field has been marked as invalid.
37102 * @param {Roo.form.Field} this
37103 * @param {String} msg The validation message
37108 * Fires after the field has been validated with no errors.
37109 * @param {Roo.form.Field} this
37114 * Fires after the key up
37115 * @param {Roo.form.Field} this
37116 * @param {Roo.EventObject} e The event Object
37123 * Returns the name attribute of the field if available
37124 * @return {String} name The field name
37126 getName: function(){
37127 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37131 onRender : function(ct, position){
37132 Roo.form.Field.superclass.onRender.call(this, ct, position);
37134 var cfg = this.getAutoCreate();
37136 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37138 if (!cfg.name.length) {
37141 if(this.inputType){
37142 cfg.type = this.inputType;
37144 this.el = ct.createChild(cfg, position);
37146 var type = this.el.dom.type;
37148 if(type == 'password'){
37151 this.el.addClass('x-form-'+type);
37154 this.el.dom.readOnly = true;
37156 if(this.tabIndex !== undefined){
37157 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37160 this.el.addClass([this.fieldClass, this.cls]);
37165 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37166 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37167 * @return {Roo.form.Field} this
37169 applyTo : function(target){
37170 this.allowDomMove = false;
37171 this.el = Roo.get(target);
37172 this.render(this.el.dom.parentNode);
37177 initValue : function(){
37178 if(this.value !== undefined){
37179 this.setValue(this.value);
37180 }else if(this.el.dom.value.length > 0){
37181 this.setValue(this.el.dom.value);
37186 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37188 isDirty : function() {
37189 if(this.disabled) {
37192 return String(this.getValue()) !== String(this.originalValue);
37196 afterRender : function(){
37197 Roo.form.Field.superclass.afterRender.call(this);
37202 fireKey : function(e){
37203 //Roo.log('field ' + e.getKey());
37204 if(e.isNavKeyPress()){
37205 this.fireEvent("specialkey", this, e);
37210 * Resets the current field value to the originally loaded value and clears any validation messages
37212 reset : function(){
37213 this.setValue(this.resetValue);
37214 this.clearInvalid();
37218 initEvents : function(){
37219 // safari killled keypress - so keydown is now used..
37220 this.el.on("keydown" , this.fireKey, this);
37221 this.el.on("focus", this.onFocus, this);
37222 this.el.on("blur", this.onBlur, this);
37223 this.el.relayEvent('keyup', this);
37225 // reference to original value for reset
37226 this.originalValue = this.getValue();
37227 this.resetValue = this.getValue();
37231 onFocus : function(){
37232 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37233 this.el.addClass(this.focusClass);
37235 if(!this.hasFocus){
37236 this.hasFocus = true;
37237 this.startValue = this.getValue();
37238 this.fireEvent("focus", this);
37242 beforeBlur : Roo.emptyFn,
37245 onBlur : function(){
37247 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37248 this.el.removeClass(this.focusClass);
37250 this.hasFocus = false;
37251 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37254 var v = this.getValue();
37255 if(String(v) !== String(this.startValue)){
37256 this.fireEvent('change', this, v, this.startValue);
37258 this.fireEvent("blur", this);
37262 * Returns whether or not the field value is currently valid
37263 * @param {Boolean} preventMark True to disable marking the field invalid
37264 * @return {Boolean} True if the value is valid, else false
37266 isValid : function(preventMark){
37270 var restore = this.preventMark;
37271 this.preventMark = preventMark === true;
37272 var v = this.validateValue(this.processValue(this.getRawValue()));
37273 this.preventMark = restore;
37278 * Validates the field value
37279 * @return {Boolean} True if the value is valid, else false
37281 validate : function(){
37282 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37283 this.clearInvalid();
37289 processValue : function(value){
37294 // Subclasses should provide the validation implementation by overriding this
37295 validateValue : function(value){
37300 * Mark this field as invalid
37301 * @param {String} msg The validation message
37303 markInvalid : function(msg){
37304 if(!this.rendered || this.preventMark){ // not rendered
37308 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37310 obj.el.addClass(this.invalidClass);
37311 msg = msg || this.invalidText;
37312 switch(this.msgTarget){
37314 obj.el.dom.qtip = msg;
37315 obj.el.dom.qclass = 'x-form-invalid-tip';
37316 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37317 Roo.QuickTips.enable();
37321 this.el.dom.title = msg;
37325 var elp = this.el.findParent('.x-form-element', 5, true);
37326 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37327 this.errorEl.setWidth(elp.getWidth(true)-20);
37329 this.errorEl.update(msg);
37330 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37333 if(!this.errorIcon){
37334 var elp = this.el.findParent('.x-form-element', 5, true);
37335 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37337 this.alignErrorIcon();
37338 this.errorIcon.dom.qtip = msg;
37339 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37340 this.errorIcon.show();
37341 this.on('resize', this.alignErrorIcon, this);
37344 var t = Roo.getDom(this.msgTarget);
37346 t.style.display = this.msgDisplay;
37349 this.fireEvent('invalid', this, msg);
37353 alignErrorIcon : function(){
37354 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37358 * Clear any invalid styles/messages for this field
37360 clearInvalid : function(){
37361 if(!this.rendered || this.preventMark){ // not rendered
37364 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37366 obj.el.removeClass(this.invalidClass);
37367 switch(this.msgTarget){
37369 obj.el.dom.qtip = '';
37372 this.el.dom.title = '';
37376 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37380 if(this.errorIcon){
37381 this.errorIcon.dom.qtip = '';
37382 this.errorIcon.hide();
37383 this.un('resize', this.alignErrorIcon, this);
37387 var t = Roo.getDom(this.msgTarget);
37389 t.style.display = 'none';
37392 this.fireEvent('valid', this);
37396 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37397 * @return {Mixed} value The field value
37399 getRawValue : function(){
37400 var v = this.el.getValue();
37406 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37407 * @return {Mixed} value The field value
37409 getValue : function(){
37410 var v = this.el.getValue();
37416 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37417 * @param {Mixed} value The value to set
37419 setRawValue : function(v){
37420 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37424 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37425 * @param {Mixed} value The value to set
37427 setValue : function(v){
37430 this.el.dom.value = (v === null || v === undefined ? '' : v);
37435 adjustSize : function(w, h){
37436 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37437 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37441 adjustWidth : function(tag, w){
37442 tag = tag.toLowerCase();
37443 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37444 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37445 if(tag == 'input'){
37448 if(tag == 'textarea'){
37451 }else if(Roo.isOpera){
37452 if(tag == 'input'){
37455 if(tag == 'textarea'){
37465 // anything other than normal should be considered experimental
37466 Roo.form.Field.msgFx = {
37468 show: function(msgEl, f){
37469 msgEl.setDisplayed('block');
37472 hide : function(msgEl, f){
37473 msgEl.setDisplayed(false).update('');
37478 show: function(msgEl, f){
37479 msgEl.slideIn('t', {stopFx:true});
37482 hide : function(msgEl, f){
37483 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37488 show: function(msgEl, f){
37489 msgEl.fixDisplay();
37490 msgEl.alignTo(f.el, 'tl-tr');
37491 msgEl.slideIn('l', {stopFx:true});
37494 hide : function(msgEl, f){
37495 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37500 * Ext JS Library 1.1.1
37501 * Copyright(c) 2006-2007, Ext JS, LLC.
37503 * Originally Released Under LGPL - original licence link has changed is not relivant.
37506 * <script type="text/javascript">
37511 * @class Roo.form.TextField
37512 * @extends Roo.form.Field
37513 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37514 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37516 * Creates a new TextField
37517 * @param {Object} config Configuration options
37519 Roo.form.TextField = function(config){
37520 Roo.form.TextField.superclass.constructor.call(this, config);
37524 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37525 * according to the default logic, but this event provides a hook for the developer to apply additional
37526 * logic at runtime to resize the field if needed.
37527 * @param {Roo.form.Field} this This text field
37528 * @param {Number} width The new field width
37534 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37536 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37540 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37544 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37548 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37552 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37556 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37558 disableKeyFilter : false,
37560 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37564 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37568 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37570 maxLength : Number.MAX_VALUE,
37572 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37574 minLengthText : "The minimum length for this field is {0}",
37576 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37578 maxLengthText : "The maximum length for this field is {0}",
37580 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37582 selectOnFocus : false,
37584 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37586 blankText : "This field is required",
37588 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37589 * If available, this function will be called only after the basic validators all return true, and will be passed the
37590 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37594 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37595 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37596 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37600 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37604 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37610 initEvents : function()
37612 if (this.emptyText) {
37613 this.el.attr('placeholder', this.emptyText);
37616 Roo.form.TextField.superclass.initEvents.call(this);
37617 if(this.validationEvent == 'keyup'){
37618 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37619 this.el.on('keyup', this.filterValidation, this);
37621 else if(this.validationEvent !== false){
37622 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37625 if(this.selectOnFocus){
37626 this.on("focus", this.preFocus, this);
37629 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37630 this.el.on("keypress", this.filterKeys, this);
37633 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37634 this.el.on("click", this.autoSize, this);
37636 if(this.el.is('input[type=password]') && Roo.isSafari){
37637 this.el.on('keydown', this.SafariOnKeyDown, this);
37641 processValue : function(value){
37642 if(this.stripCharsRe){
37643 var newValue = value.replace(this.stripCharsRe, '');
37644 if(newValue !== value){
37645 this.setRawValue(newValue);
37652 filterValidation : function(e){
37653 if(!e.isNavKeyPress()){
37654 this.validationTask.delay(this.validationDelay);
37659 onKeyUp : function(e){
37660 if(!e.isNavKeyPress()){
37666 * Resets the current field value to the originally-loaded value and clears any validation messages.
37669 reset : function(){
37670 Roo.form.TextField.superclass.reset.call(this);
37676 preFocus : function(){
37678 if(this.selectOnFocus){
37679 this.el.dom.select();
37685 filterKeys : function(e){
37686 var k = e.getKey();
37687 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37690 var c = e.getCharCode(), cc = String.fromCharCode(c);
37691 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37694 if(!this.maskRe.test(cc)){
37699 setValue : function(v){
37701 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37707 * Validates a value according to the field's validation rules and marks the field as invalid
37708 * if the validation fails
37709 * @param {Mixed} value The value to validate
37710 * @return {Boolean} True if the value is valid, else false
37712 validateValue : function(value){
37713 if(value.length < 1) { // if it's blank
37714 if(this.allowBlank){
37715 this.clearInvalid();
37718 this.markInvalid(this.blankText);
37722 if(value.length < this.minLength){
37723 this.markInvalid(String.format(this.minLengthText, this.minLength));
37726 if(value.length > this.maxLength){
37727 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37731 var vt = Roo.form.VTypes;
37732 if(!vt[this.vtype](value, this)){
37733 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37737 if(typeof this.validator == "function"){
37738 var msg = this.validator(value);
37740 this.markInvalid(msg);
37744 if(this.regex && !this.regex.test(value)){
37745 this.markInvalid(this.regexText);
37752 * Selects text in this field
37753 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37754 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37756 selectText : function(start, end){
37757 var v = this.getRawValue();
37759 start = start === undefined ? 0 : start;
37760 end = end === undefined ? v.length : end;
37761 var d = this.el.dom;
37762 if(d.setSelectionRange){
37763 d.setSelectionRange(start, end);
37764 }else if(d.createTextRange){
37765 var range = d.createTextRange();
37766 range.moveStart("character", start);
37767 range.moveEnd("character", v.length-end);
37774 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37775 * This only takes effect if grow = true, and fires the autosize event.
37777 autoSize : function(){
37778 if(!this.grow || !this.rendered){
37782 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37785 var v = el.dom.value;
37786 var d = document.createElement('div');
37787 d.appendChild(document.createTextNode(v));
37791 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37792 this.el.setWidth(w);
37793 this.fireEvent("autosize", this, w);
37797 SafariOnKeyDown : function(event)
37799 // this is a workaround for a password hang bug on chrome/ webkit.
37801 var isSelectAll = false;
37803 if(this.el.dom.selectionEnd > 0){
37804 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37806 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37807 event.preventDefault();
37812 if(isSelectAll){ // backspace and delete key
37814 event.preventDefault();
37815 // this is very hacky as keydown always get's upper case.
37817 var cc = String.fromCharCode(event.getCharCode());
37818 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37826 * Ext JS Library 1.1.1
37827 * Copyright(c) 2006-2007, Ext JS, LLC.
37829 * Originally Released Under LGPL - original licence link has changed is not relivant.
37832 * <script type="text/javascript">
37836 * @class Roo.form.Hidden
37837 * @extends Roo.form.TextField
37838 * Simple Hidden element used on forms
37840 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37843 * Creates a new Hidden form element.
37844 * @param {Object} config Configuration options
37849 // easy hidden field...
37850 Roo.form.Hidden = function(config){
37851 Roo.form.Hidden.superclass.constructor.call(this, config);
37854 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37856 inputType: 'hidden',
37859 labelSeparator: '',
37861 itemCls : 'x-form-item-display-none'
37869 * Ext JS Library 1.1.1
37870 * Copyright(c) 2006-2007, Ext JS, LLC.
37872 * Originally Released Under LGPL - original licence link has changed is not relivant.
37875 * <script type="text/javascript">
37879 * @class Roo.form.TriggerField
37880 * @extends Roo.form.TextField
37881 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37882 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37883 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37884 * for which you can provide a custom implementation. For example:
37886 var trigger = new Roo.form.TriggerField();
37887 trigger.onTriggerClick = myTriggerFn;
37888 trigger.applyTo('my-field');
37891 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37892 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37893 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37894 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37896 * Create a new TriggerField.
37897 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37898 * to the base TextField)
37900 Roo.form.TriggerField = function(config){
37901 this.mimicing = false;
37902 Roo.form.TriggerField.superclass.constructor.call(this, config);
37905 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37907 * @cfg {String} triggerClass A CSS class to apply to the trigger
37910 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37911 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37913 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37915 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37919 /** @cfg {Boolean} grow @hide */
37920 /** @cfg {Number} growMin @hide */
37921 /** @cfg {Number} growMax @hide */
37927 autoSize: Roo.emptyFn,
37931 deferHeight : true,
37934 actionMode : 'wrap',
37936 onResize : function(w, h){
37937 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37938 if(typeof w == 'number'){
37939 var x = w - this.trigger.getWidth();
37940 this.el.setWidth(this.adjustWidth('input', x));
37941 this.trigger.setStyle('left', x+'px');
37946 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37949 getResizeEl : function(){
37954 getPositionEl : function(){
37959 alignErrorIcon : function(){
37960 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37964 onRender : function(ct, position){
37965 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37966 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37967 this.trigger = this.wrap.createChild(this.triggerConfig ||
37968 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37969 if(this.hideTrigger){
37970 this.trigger.setDisplayed(false);
37972 this.initTrigger();
37974 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37979 initTrigger : function(){
37980 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37981 this.trigger.addClassOnOver('x-form-trigger-over');
37982 this.trigger.addClassOnClick('x-form-trigger-click');
37986 onDestroy : function(){
37988 this.trigger.removeAllListeners();
37989 this.trigger.remove();
37992 this.wrap.remove();
37994 Roo.form.TriggerField.superclass.onDestroy.call(this);
37998 onFocus : function(){
37999 Roo.form.TriggerField.superclass.onFocus.call(this);
38000 if(!this.mimicing){
38001 this.wrap.addClass('x-trigger-wrap-focus');
38002 this.mimicing = true;
38003 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
38004 if(this.monitorTab){
38005 this.el.on("keydown", this.checkTab, this);
38011 checkTab : function(e){
38012 if(e.getKey() == e.TAB){
38013 this.triggerBlur();
38018 onBlur : function(){
38023 mimicBlur : function(e, t){
38024 if(!this.wrap.contains(t) && this.validateBlur()){
38025 this.triggerBlur();
38030 triggerBlur : function(){
38031 this.mimicing = false;
38032 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
38033 if(this.monitorTab){
38034 this.el.un("keydown", this.checkTab, this);
38036 this.wrap.removeClass('x-trigger-wrap-focus');
38037 Roo.form.TriggerField.superclass.onBlur.call(this);
38041 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38042 validateBlur : function(e, t){
38047 onDisable : function(){
38048 Roo.form.TriggerField.superclass.onDisable.call(this);
38050 this.wrap.addClass('x-item-disabled');
38055 onEnable : function(){
38056 Roo.form.TriggerField.superclass.onEnable.call(this);
38058 this.wrap.removeClass('x-item-disabled');
38063 onShow : function(){
38064 var ae = this.getActionEl();
38067 ae.dom.style.display = '';
38068 ae.dom.style.visibility = 'visible';
38074 onHide : function(){
38075 var ae = this.getActionEl();
38076 ae.dom.style.display = 'none';
38080 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38081 * by an implementing function.
38083 * @param {EventObject} e
38085 onTriggerClick : Roo.emptyFn
38088 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38089 // to be extended by an implementing class. For an example of implementing this class, see the custom
38090 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38091 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38092 initComponent : function(){
38093 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38095 this.triggerConfig = {
38096 tag:'span', cls:'x-form-twin-triggers', cn:[
38097 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38098 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38102 getTrigger : function(index){
38103 return this.triggers[index];
38106 initTrigger : function(){
38107 var ts = this.trigger.select('.x-form-trigger', true);
38108 this.wrap.setStyle('overflow', 'hidden');
38109 var triggerField = this;
38110 ts.each(function(t, all, index){
38111 t.hide = function(){
38112 var w = triggerField.wrap.getWidth();
38113 this.dom.style.display = 'none';
38114 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38116 t.show = function(){
38117 var w = triggerField.wrap.getWidth();
38118 this.dom.style.display = '';
38119 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38121 var triggerIndex = 'Trigger'+(index+1);
38123 if(this['hide'+triggerIndex]){
38124 t.dom.style.display = 'none';
38126 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38127 t.addClassOnOver('x-form-trigger-over');
38128 t.addClassOnClick('x-form-trigger-click');
38130 this.triggers = ts.elements;
38133 onTrigger1Click : Roo.emptyFn,
38134 onTrigger2Click : Roo.emptyFn
38137 * Ext JS Library 1.1.1
38138 * Copyright(c) 2006-2007, Ext JS, LLC.
38140 * Originally Released Under LGPL - original licence link has changed is not relivant.
38143 * <script type="text/javascript">
38147 * @class Roo.form.TextArea
38148 * @extends Roo.form.TextField
38149 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38150 * support for auto-sizing.
38152 * Creates a new TextArea
38153 * @param {Object} config Configuration options
38155 Roo.form.TextArea = function(config){
38156 Roo.form.TextArea.superclass.constructor.call(this, config);
38157 // these are provided exchanges for backwards compat
38158 // minHeight/maxHeight were replaced by growMin/growMax to be
38159 // compatible with TextField growing config values
38160 if(this.minHeight !== undefined){
38161 this.growMin = this.minHeight;
38163 if(this.maxHeight !== undefined){
38164 this.growMax = this.maxHeight;
38168 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38170 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38174 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38178 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38179 * in the field (equivalent to setting overflow: hidden, defaults to false)
38181 preventScrollbars: false,
38183 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38184 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38188 onRender : function(ct, position){
38190 this.defaultAutoCreate = {
38192 style:"width:300px;height:60px;",
38193 autocomplete: "off"
38196 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38198 this.textSizeEl = Roo.DomHelper.append(document.body, {
38199 tag: "pre", cls: "x-form-grow-sizer"
38201 if(this.preventScrollbars){
38202 this.el.setStyle("overflow", "hidden");
38204 this.el.setHeight(this.growMin);
38208 onDestroy : function(){
38209 if(this.textSizeEl){
38210 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38212 Roo.form.TextArea.superclass.onDestroy.call(this);
38216 onKeyUp : function(e){
38217 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38223 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38224 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38226 autoSize : function(){
38227 if(!this.grow || !this.textSizeEl){
38231 var v = el.dom.value;
38232 var ts = this.textSizeEl;
38235 ts.appendChild(document.createTextNode(v));
38238 Roo.fly(ts).setWidth(this.el.getWidth());
38240 v = "  ";
38243 v = v.replace(/\n/g, '<p> </p>');
38245 v += " \n ";
38248 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38249 if(h != this.lastHeight){
38250 this.lastHeight = h;
38251 this.el.setHeight(h);
38252 this.fireEvent("autosize", this, h);
38257 * Ext JS Library 1.1.1
38258 * Copyright(c) 2006-2007, Ext JS, LLC.
38260 * Originally Released Under LGPL - original licence link has changed is not relivant.
38263 * <script type="text/javascript">
38268 * @class Roo.form.NumberField
38269 * @extends Roo.form.TextField
38270 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38272 * Creates a new NumberField
38273 * @param {Object} config Configuration options
38275 Roo.form.NumberField = function(config){
38276 Roo.form.NumberField.superclass.constructor.call(this, config);
38279 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38281 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38283 fieldClass: "x-form-field x-form-num-field",
38285 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38287 allowDecimals : true,
38289 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38291 decimalSeparator : ".",
38293 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38295 decimalPrecision : 2,
38297 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38299 allowNegative : true,
38301 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38303 minValue : Number.NEGATIVE_INFINITY,
38305 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38307 maxValue : Number.MAX_VALUE,
38309 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38311 minText : "The minimum value for this field is {0}",
38313 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38315 maxText : "The maximum value for this field is {0}",
38317 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38318 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38320 nanText : "{0} is not a valid number",
38323 initEvents : function(){
38324 Roo.form.NumberField.superclass.initEvents.call(this);
38325 var allowed = "0123456789";
38326 if(this.allowDecimals){
38327 allowed += this.decimalSeparator;
38329 if(this.allowNegative){
38332 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38333 var keyPress = function(e){
38334 var k = e.getKey();
38335 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38338 var c = e.getCharCode();
38339 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38343 this.el.on("keypress", keyPress, this);
38347 validateValue : function(value){
38348 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38351 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38354 var num = this.parseValue(value);
38356 this.markInvalid(String.format(this.nanText, value));
38359 if(num < this.minValue){
38360 this.markInvalid(String.format(this.minText, this.minValue));
38363 if(num > this.maxValue){
38364 this.markInvalid(String.format(this.maxText, this.maxValue));
38370 getValue : function(){
38371 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38375 parseValue : function(value){
38376 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38377 return isNaN(value) ? '' : value;
38381 fixPrecision : function(value){
38382 var nan = isNaN(value);
38383 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38384 return nan ? '' : value;
38386 return parseFloat(value).toFixed(this.decimalPrecision);
38389 setValue : function(v){
38390 v = this.fixPrecision(v);
38391 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38395 decimalPrecisionFcn : function(v){
38396 return Math.floor(v);
38399 beforeBlur : function(){
38400 var v = this.parseValue(this.getRawValue());
38407 * Ext JS Library 1.1.1
38408 * Copyright(c) 2006-2007, Ext JS, LLC.
38410 * Originally Released Under LGPL - original licence link has changed is not relivant.
38413 * <script type="text/javascript">
38417 * @class Roo.form.DateField
38418 * @extends Roo.form.TriggerField
38419 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38421 * Create a new DateField
38422 * @param {Object} config
38424 Roo.form.DateField = function(config){
38425 Roo.form.DateField.superclass.constructor.call(this, config);
38431 * Fires when a date is selected
38432 * @param {Roo.form.DateField} combo This combo box
38433 * @param {Date} date The date selected
38440 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38441 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38442 this.ddMatch = null;
38443 if(this.disabledDates){
38444 var dd = this.disabledDates;
38446 for(var i = 0; i < dd.length; i++){
38448 if(i != dd.length-1) re += "|";
38450 this.ddMatch = new RegExp(re + ")");
38454 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38456 * @cfg {String} format
38457 * The default date format string which can be overriden for localization support. The format must be
38458 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38462 * @cfg {String} altFormats
38463 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38464 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38466 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38468 * @cfg {Array} disabledDays
38469 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38471 disabledDays : null,
38473 * @cfg {String} disabledDaysText
38474 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38476 disabledDaysText : "Disabled",
38478 * @cfg {Array} disabledDates
38479 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38480 * expression so they are very powerful. Some examples:
38482 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38483 * <li>["03/08", "09/16"] would disable those days for every year</li>
38484 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38485 * <li>["03/../2006"] would disable every day in March 2006</li>
38486 * <li>["^03"] would disable every day in every March</li>
38488 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38489 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38491 disabledDates : null,
38493 * @cfg {String} disabledDatesText
38494 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38496 disabledDatesText : "Disabled",
38498 * @cfg {Date/String} minValue
38499 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38500 * valid format (defaults to null).
38504 * @cfg {Date/String} maxValue
38505 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38506 * valid format (defaults to null).
38510 * @cfg {String} minText
38511 * The error text to display when the date in the cell is before minValue (defaults to
38512 * 'The date in this field must be after {minValue}').
38514 minText : "The date in this field must be equal to or after {0}",
38516 * @cfg {String} maxText
38517 * The error text to display when the date in the cell is after maxValue (defaults to
38518 * 'The date in this field must be before {maxValue}').
38520 maxText : "The date in this field must be equal to or before {0}",
38522 * @cfg {String} invalidText
38523 * The error text to display when the date in the field is invalid (defaults to
38524 * '{value} is not a valid date - it must be in the format {format}').
38526 invalidText : "{0} is not a valid date - it must be in the format {1}",
38528 * @cfg {String} triggerClass
38529 * An additional CSS class used to style the trigger button. The trigger will always get the
38530 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38531 * which displays a calendar icon).
38533 triggerClass : 'x-form-date-trigger',
38537 * @cfg {Boolean} useIso
38538 * if enabled, then the date field will use a hidden field to store the
38539 * real value as iso formated date. default (false)
38543 * @cfg {String/Object} autoCreate
38544 * A DomHelper element spec, or true for a default element spec (defaults to
38545 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38548 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38551 hiddenField: false,
38553 onRender : function(ct, position)
38555 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38557 //this.el.dom.removeAttribute('name');
38558 Roo.log("Changing name?");
38559 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38560 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38562 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38563 // prevent input submission
38564 this.hiddenName = this.name;
38571 validateValue : function(value)
38573 value = this.formatDate(value);
38574 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38575 Roo.log('super failed');
38578 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38581 var svalue = value;
38582 value = this.parseDate(value);
38584 Roo.log('parse date failed' + svalue);
38585 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38588 var time = value.getTime();
38589 if(this.minValue && time < this.minValue.getTime()){
38590 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38593 if(this.maxValue && time > this.maxValue.getTime()){
38594 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38597 if(this.disabledDays){
38598 var day = value.getDay();
38599 for(var i = 0; i < this.disabledDays.length; i++) {
38600 if(day === this.disabledDays[i]){
38601 this.markInvalid(this.disabledDaysText);
38606 var fvalue = this.formatDate(value);
38607 if(this.ddMatch && this.ddMatch.test(fvalue)){
38608 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38615 // Provides logic to override the default TriggerField.validateBlur which just returns true
38616 validateBlur : function(){
38617 return !this.menu || !this.menu.isVisible();
38620 getName: function()
38622 // returns hidden if it's set..
38623 if (!this.rendered) {return ''};
38624 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38629 * Returns the current date value of the date field.
38630 * @return {Date} The date value
38632 getValue : function(){
38634 return this.hiddenField ?
38635 this.hiddenField.value :
38636 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38640 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38641 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38642 * (the default format used is "m/d/y").
38645 //All of these calls set the same date value (May 4, 2006)
38647 //Pass a date object:
38648 var dt = new Date('5/4/06');
38649 dateField.setValue(dt);
38651 //Pass a date string (default format):
38652 dateField.setValue('5/4/06');
38654 //Pass a date string (custom format):
38655 dateField.format = 'Y-m-d';
38656 dateField.setValue('2006-5-4');
38658 * @param {String/Date} date The date or valid date string
38660 setValue : function(date){
38661 if (this.hiddenField) {
38662 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38664 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38665 // make sure the value field is always stored as a date..
38666 this.value = this.parseDate(date);
38672 parseDate : function(value){
38673 if(!value || value instanceof Date){
38676 var v = Date.parseDate(value, this.format);
38677 if (!v && this.useIso) {
38678 v = Date.parseDate(value, 'Y-m-d');
38680 if(!v && this.altFormats){
38681 if(!this.altFormatsArray){
38682 this.altFormatsArray = this.altFormats.split("|");
38684 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38685 v = Date.parseDate(value, this.altFormatsArray[i]);
38692 formatDate : function(date, fmt){
38693 return (!date || !(date instanceof Date)) ?
38694 date : date.dateFormat(fmt || this.format);
38699 select: function(m, d){
38702 this.fireEvent('select', this, d);
38704 show : function(){ // retain focus styling
38708 this.focus.defer(10, this);
38709 var ml = this.menuListeners;
38710 this.menu.un("select", ml.select, this);
38711 this.menu.un("show", ml.show, this);
38712 this.menu.un("hide", ml.hide, this);
38717 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38718 onTriggerClick : function(){
38722 if(this.menu == null){
38723 this.menu = new Roo.menu.DateMenu();
38725 Roo.apply(this.menu.picker, {
38726 showClear: this.allowBlank,
38727 minDate : this.minValue,
38728 maxDate : this.maxValue,
38729 disabledDatesRE : this.ddMatch,
38730 disabledDatesText : this.disabledDatesText,
38731 disabledDays : this.disabledDays,
38732 disabledDaysText : this.disabledDaysText,
38733 format : this.useIso ? 'Y-m-d' : this.format,
38734 minText : String.format(this.minText, this.formatDate(this.minValue)),
38735 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38737 this.menu.on(Roo.apply({}, this.menuListeners, {
38740 this.menu.picker.setValue(this.getValue() || new Date());
38741 this.menu.show(this.el, "tl-bl?");
38744 beforeBlur : function(){
38745 var v = this.parseDate(this.getRawValue());
38755 isDirty : function() {
38756 if(this.disabled) {
38760 if(typeof(this.startValue) === 'undefined'){
38764 return String(this.getValue()) !== String(this.startValue);
38769 * Ext JS Library 1.1.1
38770 * Copyright(c) 2006-2007, Ext JS, LLC.
38772 * Originally Released Under LGPL - original licence link has changed is not relivant.
38775 * <script type="text/javascript">
38779 * @class Roo.form.MonthField
38780 * @extends Roo.form.TriggerField
38781 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38783 * Create a new MonthField
38784 * @param {Object} config
38786 Roo.form.MonthField = function(config){
38788 Roo.form.MonthField.superclass.constructor.call(this, config);
38794 * Fires when a date is selected
38795 * @param {Roo.form.MonthFieeld} combo This combo box
38796 * @param {Date} date The date selected
38803 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38804 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38805 this.ddMatch = null;
38806 if(this.disabledDates){
38807 var dd = this.disabledDates;
38809 for(var i = 0; i < dd.length; i++){
38811 if(i != dd.length-1) re += "|";
38813 this.ddMatch = new RegExp(re + ")");
38817 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38819 * @cfg {String} format
38820 * The default date format string which can be overriden for localization support. The format must be
38821 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38825 * @cfg {String} altFormats
38826 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38827 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38829 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38831 * @cfg {Array} disabledDays
38832 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38834 disabledDays : [0,1,2,3,4,5,6],
38836 * @cfg {String} disabledDaysText
38837 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38839 disabledDaysText : "Disabled",
38841 * @cfg {Array} disabledDates
38842 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38843 * expression so they are very powerful. Some examples:
38845 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38846 * <li>["03/08", "09/16"] would disable those days for every year</li>
38847 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38848 * <li>["03/../2006"] would disable every day in March 2006</li>
38849 * <li>["^03"] would disable every day in every March</li>
38851 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38852 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38854 disabledDates : null,
38856 * @cfg {String} disabledDatesText
38857 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38859 disabledDatesText : "Disabled",
38861 * @cfg {Date/String} minValue
38862 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38863 * valid format (defaults to null).
38867 * @cfg {Date/String} maxValue
38868 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38869 * valid format (defaults to null).
38873 * @cfg {String} minText
38874 * The error text to display when the date in the cell is before minValue (defaults to
38875 * 'The date in this field must be after {minValue}').
38877 minText : "The date in this field must be equal to or after {0}",
38879 * @cfg {String} maxTextf
38880 * The error text to display when the date in the cell is after maxValue (defaults to
38881 * 'The date in this field must be before {maxValue}').
38883 maxText : "The date in this field must be equal to or before {0}",
38885 * @cfg {String} invalidText
38886 * The error text to display when the date in the field is invalid (defaults to
38887 * '{value} is not a valid date - it must be in the format {format}').
38889 invalidText : "{0} is not a valid date - it must be in the format {1}",
38891 * @cfg {String} triggerClass
38892 * An additional CSS class used to style the trigger button. The trigger will always get the
38893 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38894 * which displays a calendar icon).
38896 triggerClass : 'x-form-date-trigger',
38900 * @cfg {Boolean} useIso
38901 * if enabled, then the date field will use a hidden field to store the
38902 * real value as iso formated date. default (true)
38906 * @cfg {String/Object} autoCreate
38907 * A DomHelper element spec, or true for a default element spec (defaults to
38908 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38911 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38914 hiddenField: false,
38916 hideMonthPicker : false,
38918 onRender : function(ct, position)
38920 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38922 this.el.dom.removeAttribute('name');
38923 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38925 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38926 // prevent input submission
38927 this.hiddenName = this.name;
38934 validateValue : function(value)
38936 value = this.formatDate(value);
38937 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38940 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38943 var svalue = value;
38944 value = this.parseDate(value);
38946 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38949 var time = value.getTime();
38950 if(this.minValue && time < this.minValue.getTime()){
38951 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38954 if(this.maxValue && time > this.maxValue.getTime()){
38955 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38958 /*if(this.disabledDays){
38959 var day = value.getDay();
38960 for(var i = 0; i < this.disabledDays.length; i++) {
38961 if(day === this.disabledDays[i]){
38962 this.markInvalid(this.disabledDaysText);
38968 var fvalue = this.formatDate(value);
38969 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38970 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38978 // Provides logic to override the default TriggerField.validateBlur which just returns true
38979 validateBlur : function(){
38980 return !this.menu || !this.menu.isVisible();
38984 * Returns the current date value of the date field.
38985 * @return {Date} The date value
38987 getValue : function(){
38991 return this.hiddenField ?
38992 this.hiddenField.value :
38993 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38997 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38998 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38999 * (the default format used is "m/d/y").
39002 //All of these calls set the same date value (May 4, 2006)
39004 //Pass a date object:
39005 var dt = new Date('5/4/06');
39006 monthField.setValue(dt);
39008 //Pass a date string (default format):
39009 monthField.setValue('5/4/06');
39011 //Pass a date string (custom format):
39012 monthField.format = 'Y-m-d';
39013 monthField.setValue('2006-5-4');
39015 * @param {String/Date} date The date or valid date string
39017 setValue : function(date){
39018 Roo.log('month setValue' + date);
39019 // can only be first of month..
39021 var val = this.parseDate(date);
39023 if (this.hiddenField) {
39024 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
39026 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
39027 this.value = this.parseDate(date);
39031 parseDate : function(value){
39032 if(!value || value instanceof Date){
39033 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39036 var v = Date.parseDate(value, this.format);
39037 if (!v && this.useIso) {
39038 v = Date.parseDate(value, 'Y-m-d');
39042 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39046 if(!v && this.altFormats){
39047 if(!this.altFormatsArray){
39048 this.altFormatsArray = this.altFormats.split("|");
39050 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39051 v = Date.parseDate(value, this.altFormatsArray[i]);
39058 formatDate : function(date, fmt){
39059 return (!date || !(date instanceof Date)) ?
39060 date : date.dateFormat(fmt || this.format);
39065 select: function(m, d){
39067 this.fireEvent('select', this, d);
39069 show : function(){ // retain focus styling
39073 this.focus.defer(10, this);
39074 var ml = this.menuListeners;
39075 this.menu.un("select", ml.select, this);
39076 this.menu.un("show", ml.show, this);
39077 this.menu.un("hide", ml.hide, this);
39081 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39082 onTriggerClick : function(){
39086 if(this.menu == null){
39087 this.menu = new Roo.menu.DateMenu();
39091 Roo.apply(this.menu.picker, {
39093 showClear: this.allowBlank,
39094 minDate : this.minValue,
39095 maxDate : this.maxValue,
39096 disabledDatesRE : this.ddMatch,
39097 disabledDatesText : this.disabledDatesText,
39099 format : this.useIso ? 'Y-m-d' : this.format,
39100 minText : String.format(this.minText, this.formatDate(this.minValue)),
39101 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39104 this.menu.on(Roo.apply({}, this.menuListeners, {
39112 // hide month picker get's called when we called by 'before hide';
39114 var ignorehide = true;
39115 p.hideMonthPicker = function(disableAnim){
39119 if(this.monthPicker){
39120 Roo.log("hideMonthPicker called");
39121 if(disableAnim === true){
39122 this.monthPicker.hide();
39124 this.monthPicker.slideOut('t', {duration:.2});
39125 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39126 p.fireEvent("select", this, this.value);
39132 Roo.log('picker set value');
39133 Roo.log(this.getValue());
39134 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39135 m.show(this.el, 'tl-bl?');
39136 ignorehide = false;
39137 // this will trigger hideMonthPicker..
39140 // hidden the day picker
39141 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39147 p.showMonthPicker.defer(100, p);
39153 beforeBlur : function(){
39154 var v = this.parseDate(this.getRawValue());
39160 /** @cfg {Boolean} grow @hide */
39161 /** @cfg {Number} growMin @hide */
39162 /** @cfg {Number} growMax @hide */
39169 * Ext JS Library 1.1.1
39170 * Copyright(c) 2006-2007, Ext JS, LLC.
39172 * Originally Released Under LGPL - original licence link has changed is not relivant.
39175 * <script type="text/javascript">
39180 * @class Roo.form.ComboBox
39181 * @extends Roo.form.TriggerField
39182 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39184 * Create a new ComboBox.
39185 * @param {Object} config Configuration options
39187 Roo.form.ComboBox = function(config){
39188 Roo.form.ComboBox.superclass.constructor.call(this, config);
39192 * Fires when the dropdown list is expanded
39193 * @param {Roo.form.ComboBox} combo This combo box
39198 * Fires when the dropdown list is collapsed
39199 * @param {Roo.form.ComboBox} combo This combo box
39203 * @event beforeselect
39204 * Fires before a list item is selected. Return false to cancel the selection.
39205 * @param {Roo.form.ComboBox} combo This combo box
39206 * @param {Roo.data.Record} record The data record returned from the underlying store
39207 * @param {Number} index The index of the selected item in the dropdown list
39209 'beforeselect' : true,
39212 * Fires when a list item is selected
39213 * @param {Roo.form.ComboBox} combo This combo box
39214 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39215 * @param {Number} index The index of the selected item in the dropdown list
39219 * @event beforequery
39220 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39221 * The event object passed has these properties:
39222 * @param {Roo.form.ComboBox} combo This combo box
39223 * @param {String} query The query
39224 * @param {Boolean} forceAll true to force "all" query
39225 * @param {Boolean} cancel true to cancel the query
39226 * @param {Object} e The query event object
39228 'beforequery': true,
39231 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39232 * @param {Roo.form.ComboBox} combo This combo box
39237 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39238 * @param {Roo.form.ComboBox} combo This combo box
39239 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39245 if(this.transform){
39246 this.allowDomMove = false;
39247 var s = Roo.getDom(this.transform);
39248 if(!this.hiddenName){
39249 this.hiddenName = s.name;
39252 this.mode = 'local';
39253 var d = [], opts = s.options;
39254 for(var i = 0, len = opts.length;i < len; i++){
39256 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39258 this.value = value;
39260 d.push([value, o.text]);
39262 this.store = new Roo.data.SimpleStore({
39264 fields: ['value', 'text'],
39267 this.valueField = 'value';
39268 this.displayField = 'text';
39270 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39271 if(!this.lazyRender){
39272 this.target = true;
39273 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39274 s.parentNode.removeChild(s); // remove it
39275 this.render(this.el.parentNode);
39277 s.parentNode.removeChild(s); // remove it
39282 this.store = Roo.factory(this.store, Roo.data);
39285 this.selectedIndex = -1;
39286 if(this.mode == 'local'){
39287 if(config.queryDelay === undefined){
39288 this.queryDelay = 10;
39290 if(config.minChars === undefined){
39296 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39298 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39301 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39302 * rendering into an Roo.Editor, defaults to false)
39305 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39306 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39309 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39312 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39313 * the dropdown list (defaults to undefined, with no header element)
39317 * @cfg {String/Roo.Template} tpl The template to use to render the output
39321 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39323 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39325 listWidth: undefined,
39327 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39328 * mode = 'remote' or 'text' if mode = 'local')
39330 displayField: undefined,
39332 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39333 * mode = 'remote' or 'value' if mode = 'local').
39334 * Note: use of a valueField requires the user make a selection
39335 * in order for a value to be mapped.
39337 valueField: undefined,
39341 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39342 * field's data value (defaults to the underlying DOM element's name)
39344 hiddenName: undefined,
39346 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39350 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39352 selectedClass: 'x-combo-selected',
39354 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39355 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39356 * which displays a downward arrow icon).
39358 triggerClass : 'x-form-arrow-trigger',
39360 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39364 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39365 * anchor positions (defaults to 'tl-bl')
39367 listAlign: 'tl-bl?',
39369 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39373 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39374 * query specified by the allQuery config option (defaults to 'query')
39376 triggerAction: 'query',
39378 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39379 * (defaults to 4, does not apply if editable = false)
39383 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39384 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39388 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39389 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39393 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39394 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39398 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39399 * when editable = true (defaults to false)
39401 selectOnFocus:false,
39403 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39405 queryParam: 'query',
39407 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39408 * when mode = 'remote' (defaults to 'Loading...')
39410 loadingText: 'Loading...',
39412 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39416 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39420 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39421 * traditional select (defaults to true)
39425 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39429 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39433 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39434 * listWidth has a higher value)
39438 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39439 * allow the user to set arbitrary text into the field (defaults to false)
39441 forceSelection:false,
39443 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39444 * if typeAhead = true (defaults to 250)
39446 typeAheadDelay : 250,
39448 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39449 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39451 valueNotFoundText : undefined,
39453 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39455 blockFocus : false,
39458 * @cfg {Boolean} disableClear Disable showing of clear button.
39460 disableClear : false,
39462 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39464 alwaysQuery : false,
39470 // element that contains real text value.. (when hidden is used..)
39473 onRender : function(ct, position){
39474 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39475 if(this.hiddenName){
39476 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39478 this.hiddenField.value =
39479 this.hiddenValue !== undefined ? this.hiddenValue :
39480 this.value !== undefined ? this.value : '';
39482 // prevent input submission
39483 this.el.dom.removeAttribute('name');
39488 this.el.dom.setAttribute('autocomplete', 'off');
39491 var cls = 'x-combo-list';
39493 this.list = new Roo.Layer({
39494 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39497 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39498 this.list.setWidth(lw);
39499 this.list.swallowEvent('mousewheel');
39500 this.assetHeight = 0;
39503 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39504 this.assetHeight += this.header.getHeight();
39507 this.innerList = this.list.createChild({cls:cls+'-inner'});
39508 this.innerList.on('mouseover', this.onViewOver, this);
39509 this.innerList.on('mousemove', this.onViewMove, this);
39510 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39512 if(this.allowBlank && !this.pageSize && !this.disableClear){
39513 this.footer = this.list.createChild({cls:cls+'-ft'});
39514 this.pageTb = new Roo.Toolbar(this.footer);
39518 this.footer = this.list.createChild({cls:cls+'-ft'});
39519 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39520 {pageSize: this.pageSize});
39524 if (this.pageTb && this.allowBlank && !this.disableClear) {
39526 this.pageTb.add(new Roo.Toolbar.Fill(), {
39527 cls: 'x-btn-icon x-btn-clear',
39529 handler: function()
39532 _this.clearValue();
39533 _this.onSelect(false, -1);
39538 this.assetHeight += this.footer.getHeight();
39543 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39546 this.view = new Roo.View(this.innerList, this.tpl, {
39547 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39550 this.view.on('click', this.onViewClick, this);
39552 this.store.on('beforeload', this.onBeforeLoad, this);
39553 this.store.on('load', this.onLoad, this);
39554 this.store.on('loadexception', this.onLoadException, this);
39556 if(this.resizable){
39557 this.resizer = new Roo.Resizable(this.list, {
39558 pinned:true, handles:'se'
39560 this.resizer.on('resize', function(r, w, h){
39561 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39562 this.listWidth = w;
39563 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39564 this.restrictHeight();
39566 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39568 if(!this.editable){
39569 this.editable = true;
39570 this.setEditable(false);
39574 if (typeof(this.events.add.listeners) != 'undefined') {
39576 this.addicon = this.wrap.createChild(
39577 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39579 this.addicon.on('click', function(e) {
39580 this.fireEvent('add', this);
39583 if (typeof(this.events.edit.listeners) != 'undefined') {
39585 this.editicon = this.wrap.createChild(
39586 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39587 if (this.addicon) {
39588 this.editicon.setStyle('margin-left', '40px');
39590 this.editicon.on('click', function(e) {
39592 // we fire even if inothing is selected..
39593 this.fireEvent('edit', this, this.lastData );
39603 initEvents : function(){
39604 Roo.form.ComboBox.superclass.initEvents.call(this);
39606 this.keyNav = new Roo.KeyNav(this.el, {
39607 "up" : function(e){
39608 this.inKeyMode = true;
39612 "down" : function(e){
39613 if(!this.isExpanded()){
39614 this.onTriggerClick();
39616 this.inKeyMode = true;
39621 "enter" : function(e){
39622 this.onViewClick();
39626 "esc" : function(e){
39630 "tab" : function(e){
39631 this.onViewClick(false);
39632 this.fireEvent("specialkey", this, e);
39638 doRelay : function(foo, bar, hname){
39639 if(hname == 'down' || this.scope.isExpanded()){
39640 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39647 this.queryDelay = Math.max(this.queryDelay || 10,
39648 this.mode == 'local' ? 10 : 250);
39649 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39650 if(this.typeAhead){
39651 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39653 if(this.editable !== false){
39654 this.el.on("keyup", this.onKeyUp, this);
39656 if(this.forceSelection){
39657 this.on('blur', this.doForce, this);
39661 onDestroy : function(){
39663 this.view.setStore(null);
39664 this.view.el.removeAllListeners();
39665 this.view.el.remove();
39666 this.view.purgeListeners();
39669 this.list.destroy();
39672 this.store.un('beforeload', this.onBeforeLoad, this);
39673 this.store.un('load', this.onLoad, this);
39674 this.store.un('loadexception', this.onLoadException, this);
39676 Roo.form.ComboBox.superclass.onDestroy.call(this);
39680 fireKey : function(e){
39681 if(e.isNavKeyPress() && !this.list.isVisible()){
39682 this.fireEvent("specialkey", this, e);
39687 onResize: function(w, h){
39688 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39690 if(typeof w != 'number'){
39691 // we do not handle it!?!?
39694 var tw = this.trigger.getWidth();
39695 tw += this.addicon ? this.addicon.getWidth() : 0;
39696 tw += this.editicon ? this.editicon.getWidth() : 0;
39698 this.el.setWidth( this.adjustWidth('input', x));
39700 this.trigger.setStyle('left', x+'px');
39702 if(this.list && this.listWidth === undefined){
39703 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39704 this.list.setWidth(lw);
39705 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39713 * Allow or prevent the user from directly editing the field text. If false is passed,
39714 * the user will only be able to select from the items defined in the dropdown list. This method
39715 * is the runtime equivalent of setting the 'editable' config option at config time.
39716 * @param {Boolean} value True to allow the user to directly edit the field text
39718 setEditable : function(value){
39719 if(value == this.editable){
39722 this.editable = value;
39724 this.el.dom.setAttribute('readOnly', true);
39725 this.el.on('mousedown', this.onTriggerClick, this);
39726 this.el.addClass('x-combo-noedit');
39728 this.el.dom.setAttribute('readOnly', false);
39729 this.el.un('mousedown', this.onTriggerClick, this);
39730 this.el.removeClass('x-combo-noedit');
39735 onBeforeLoad : function(){
39736 if(!this.hasFocus){
39739 this.innerList.update(this.loadingText ?
39740 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39741 this.restrictHeight();
39742 this.selectedIndex = -1;
39746 onLoad : function(){
39747 if(!this.hasFocus){
39750 if(this.store.getCount() > 0){
39752 this.restrictHeight();
39753 if(this.lastQuery == this.allQuery){
39755 this.el.dom.select();
39757 if(!this.selectByValue(this.value, true)){
39758 this.select(0, true);
39762 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39763 this.taTask.delay(this.typeAheadDelay);
39767 this.onEmptyResults();
39772 onLoadException : function()
39775 Roo.log(this.store.reader.jsonData);
39776 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39777 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39783 onTypeAhead : function(){
39784 if(this.store.getCount() > 0){
39785 var r = this.store.getAt(0);
39786 var newValue = r.data[this.displayField];
39787 var len = newValue.length;
39788 var selStart = this.getRawValue().length;
39789 if(selStart != len){
39790 this.setRawValue(newValue);
39791 this.selectText(selStart, newValue.length);
39797 onSelect : function(record, index){
39798 if(this.fireEvent('beforeselect', this, record, index) !== false){
39799 this.setFromData(index > -1 ? record.data : false);
39801 this.fireEvent('select', this, record, index);
39806 * Returns the currently selected field value or empty string if no value is set.
39807 * @return {String} value The selected value
39809 getValue : function(){
39810 if(this.valueField){
39811 return typeof this.value != 'undefined' ? this.value : '';
39813 return Roo.form.ComboBox.superclass.getValue.call(this);
39818 * Clears any text/value currently set in the field
39820 clearValue : function(){
39821 if(this.hiddenField){
39822 this.hiddenField.value = '';
39825 this.setRawValue('');
39826 this.lastSelectionText = '';
39831 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39832 * will be displayed in the field. If the value does not match the data value of an existing item,
39833 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39834 * Otherwise the field will be blank (although the value will still be set).
39835 * @param {String} value The value to match
39837 setValue : function(v){
39839 if(this.valueField){
39840 var r = this.findRecord(this.valueField, v);
39842 text = r.data[this.displayField];
39843 }else if(this.valueNotFoundText !== undefined){
39844 text = this.valueNotFoundText;
39847 this.lastSelectionText = text;
39848 if(this.hiddenField){
39849 this.hiddenField.value = v;
39851 Roo.form.ComboBox.superclass.setValue.call(this, text);
39855 * @property {Object} the last set data for the element
39860 * Sets the value of the field based on a object which is related to the record format for the store.
39861 * @param {Object} value the value to set as. or false on reset?
39863 setFromData : function(o){
39864 var dv = ''; // display value
39865 var vv = ''; // value value..
39867 if (this.displayField) {
39868 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39870 // this is an error condition!!!
39871 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39874 if(this.valueField){
39875 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39877 if(this.hiddenField){
39878 this.hiddenField.value = vv;
39880 this.lastSelectionText = dv;
39881 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39885 // no hidden field.. - we store the value in 'value', but still display
39886 // display field!!!!
39887 this.lastSelectionText = dv;
39888 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39894 reset : function(){
39895 // overridden so that last data is reset..
39896 this.setValue(this.resetValue);
39897 this.clearInvalid();
39898 this.lastData = false;
39900 this.view.clearSelections();
39904 findRecord : function(prop, value){
39906 if(this.store.getCount() > 0){
39907 this.store.each(function(r){
39908 if(r.data[prop] == value){
39918 getName: function()
39920 // returns hidden if it's set..
39921 if (!this.rendered) {return ''};
39922 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39926 onViewMove : function(e, t){
39927 this.inKeyMode = false;
39931 onViewOver : function(e, t){
39932 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39935 var item = this.view.findItemFromChild(t);
39937 var index = this.view.indexOf(item);
39938 this.select(index, false);
39943 onViewClick : function(doFocus)
39945 var index = this.view.getSelectedIndexes()[0];
39946 var r = this.store.getAt(index);
39948 this.onSelect(r, index);
39950 if(doFocus !== false && !this.blockFocus){
39956 restrictHeight : function(){
39957 this.innerList.dom.style.height = '';
39958 var inner = this.innerList.dom;
39959 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39960 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39961 this.list.beginUpdate();
39962 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39963 this.list.alignTo(this.el, this.listAlign);
39964 this.list.endUpdate();
39968 onEmptyResults : function(){
39973 * Returns true if the dropdown list is expanded, else false.
39975 isExpanded : function(){
39976 return this.list.isVisible();
39980 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39981 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39982 * @param {String} value The data value of the item to select
39983 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39984 * selected item if it is not currently in view (defaults to true)
39985 * @return {Boolean} True if the value matched an item in the list, else false
39987 selectByValue : function(v, scrollIntoView){
39988 if(v !== undefined && v !== null){
39989 var r = this.findRecord(this.valueField || this.displayField, v);
39991 this.select(this.store.indexOf(r), scrollIntoView);
39999 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
40000 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40001 * @param {Number} index The zero-based index of the list item to select
40002 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40003 * selected item if it is not currently in view (defaults to true)
40005 select : function(index, scrollIntoView){
40006 this.selectedIndex = index;
40007 this.view.select(index);
40008 if(scrollIntoView !== false){
40009 var el = this.view.getNode(index);
40011 this.innerList.scrollChildIntoView(el, false);
40017 selectNext : function(){
40018 var ct = this.store.getCount();
40020 if(this.selectedIndex == -1){
40022 }else if(this.selectedIndex < ct-1){
40023 this.select(this.selectedIndex+1);
40029 selectPrev : function(){
40030 var ct = this.store.getCount();
40032 if(this.selectedIndex == -1){
40034 }else if(this.selectedIndex != 0){
40035 this.select(this.selectedIndex-1);
40041 onKeyUp : function(e){
40042 if(this.editable !== false && !e.isSpecialKey()){
40043 this.lastKey = e.getKey();
40044 this.dqTask.delay(this.queryDelay);
40049 validateBlur : function(){
40050 return !this.list || !this.list.isVisible();
40054 initQuery : function(){
40055 this.doQuery(this.getRawValue());
40059 doForce : function(){
40060 if(this.el.dom.value.length > 0){
40061 this.el.dom.value =
40062 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40068 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40069 * query allowing the query action to be canceled if needed.
40070 * @param {String} query The SQL query to execute
40071 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40072 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40073 * saved in the current store (defaults to false)
40075 doQuery : function(q, forceAll){
40076 if(q === undefined || q === null){
40081 forceAll: forceAll,
40085 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40089 forceAll = qe.forceAll;
40090 if(forceAll === true || (q.length >= this.minChars)){
40091 if(this.lastQuery != q || this.alwaysQuery){
40092 this.lastQuery = q;
40093 if(this.mode == 'local'){
40094 this.selectedIndex = -1;
40096 this.store.clearFilter();
40098 this.store.filter(this.displayField, q);
40102 this.store.baseParams[this.queryParam] = q;
40104 params: this.getParams(q)
40109 this.selectedIndex = -1;
40116 getParams : function(q){
40118 //p[this.queryParam] = q;
40121 p.limit = this.pageSize;
40127 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40129 collapse : function(){
40130 if(!this.isExpanded()){
40134 Roo.get(document).un('mousedown', this.collapseIf, this);
40135 Roo.get(document).un('mousewheel', this.collapseIf, this);
40136 if (!this.editable) {
40137 Roo.get(document).un('keydown', this.listKeyPress, this);
40139 this.fireEvent('collapse', this);
40143 collapseIf : function(e){
40144 if(!e.within(this.wrap) && !e.within(this.list)){
40150 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40152 expand : function(){
40153 if(this.isExpanded() || !this.hasFocus){
40156 this.list.alignTo(this.el, this.listAlign);
40158 Roo.get(document).on('mousedown', this.collapseIf, this);
40159 Roo.get(document).on('mousewheel', this.collapseIf, this);
40160 if (!this.editable) {
40161 Roo.get(document).on('keydown', this.listKeyPress, this);
40164 this.fireEvent('expand', this);
40168 // Implements the default empty TriggerField.onTriggerClick function
40169 onTriggerClick : function(){
40173 if(this.isExpanded()){
40175 if (!this.blockFocus) {
40180 this.hasFocus = true;
40181 if(this.triggerAction == 'all') {
40182 this.doQuery(this.allQuery, true);
40184 this.doQuery(this.getRawValue());
40186 if (!this.blockFocus) {
40191 listKeyPress : function(e)
40193 //Roo.log('listkeypress');
40194 // scroll to first matching element based on key pres..
40195 if (e.isSpecialKey()) {
40198 var k = String.fromCharCode(e.getKey()).toUpperCase();
40201 var csel = this.view.getSelectedNodes();
40202 var cselitem = false;
40204 var ix = this.view.indexOf(csel[0]);
40205 cselitem = this.store.getAt(ix);
40206 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40212 this.store.each(function(v) {
40214 // start at existing selection.
40215 if (cselitem.id == v.id) {
40221 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40222 match = this.store.indexOf(v);
40227 if (match === false) {
40228 return true; // no more action?
40231 this.view.select(match);
40232 var sn = Roo.get(this.view.getSelectedNodes()[0])
40233 sn.scrollIntoView(sn.dom.parentNode, false);
40237 * @cfg {Boolean} grow
40241 * @cfg {Number} growMin
40245 * @cfg {Number} growMax
40253 * Copyright(c) 2010-2012, Roo J Solutions Limited
40260 * @class Roo.form.ComboBoxArray
40261 * @extends Roo.form.TextField
40262 * A facebook style adder... for lists of email / people / countries etc...
40263 * pick multiple items from a combo box, and shows each one.
40265 * Fred [x] Brian [x] [Pick another |v]
40268 * For this to work: it needs various extra information
40269 * - normal combo problay has
40271 * + displayField, valueField
40273 * For our purpose...
40276 * If we change from 'extends' to wrapping...
40283 * Create a new ComboBoxArray.
40284 * @param {Object} config Configuration options
40288 Roo.form.ComboBoxArray = function(config)
40293 * Fires when remove the value from the list
40294 * @param {Roo.form.ComboBoxArray} _self This combo box array
40295 * @param {Roo.form.ComboBoxArray.Item} item removed item
40302 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40304 this.items = new Roo.util.MixedCollection(false);
40306 // construct the child combo...
40316 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40319 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40324 // behavies liek a hiddne field
40325 inputType: 'hidden',
40327 * @cfg {Number} width The width of the box that displays the selected element
40334 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40338 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40340 hiddenName : false,
40343 // private the array of items that are displayed..
40345 // private - the hidden field el.
40347 // private - the filed el..
40350 //validateValue : function() { return true; }, // all values are ok!
40351 //onAddClick: function() { },
40353 onRender : function(ct, position)
40356 // create the standard hidden element
40357 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40360 // give fake names to child combo;
40361 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40362 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40364 this.combo = Roo.factory(this.combo, Roo.form);
40365 this.combo.onRender(ct, position);
40366 if (typeof(this.combo.width) != 'undefined') {
40367 this.combo.onResize(this.combo.width,0);
40370 this.combo.initEvents();
40372 // assigned so form know we need to do this..
40373 this.store = this.combo.store;
40374 this.valueField = this.combo.valueField;
40375 this.displayField = this.combo.displayField ;
40378 this.combo.wrap.addClass('x-cbarray-grp');
40380 var cbwrap = this.combo.wrap.createChild(
40381 {tag: 'div', cls: 'x-cbarray-cb'},
40386 this.hiddenEl = this.combo.wrap.createChild({
40387 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40389 this.el = this.combo.wrap.createChild({
40390 tag: 'input', type:'hidden' , name: this.name, value : ''
40392 // this.el.dom.removeAttribute("name");
40395 this.outerWrap = this.combo.wrap;
40396 this.wrap = cbwrap;
40398 this.outerWrap.setWidth(this.width);
40399 this.outerWrap.dom.removeChild(this.el.dom);
40401 this.wrap.dom.appendChild(this.el.dom);
40402 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40403 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40405 this.combo.trigger.setStyle('position','relative');
40406 this.combo.trigger.setStyle('left', '0px');
40407 this.combo.trigger.setStyle('top', '2px');
40409 this.combo.el.setStyle('vertical-align', 'text-bottom');
40411 //this.trigger.setStyle('vertical-align', 'top');
40413 // this should use the code from combo really... on('add' ....)
40417 this.adder = this.outerWrap.createChild(
40418 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40420 this.adder.on('click', function(e) {
40421 _t.fireEvent('adderclick', this, e);
40425 //this.adder.on('click', this.onAddClick, _t);
40428 this.combo.on('select', function(cb, rec, ix) {
40429 this.addItem(rec.data);
40432 cb.el.dom.value = '';
40433 //cb.lastData = rec.data;
40442 getName: function()
40444 // returns hidden if it's set..
40445 if (!this.rendered) {return ''};
40446 return this.hiddenName ? this.hiddenName : this.name;
40451 onResize: function(w, h){
40454 // not sure if this is needed..
40455 //this.combo.onResize(w,h);
40457 if(typeof w != 'number'){
40458 // we do not handle it!?!?
40461 var tw = this.combo.trigger.getWidth();
40462 tw += this.addicon ? this.addicon.getWidth() : 0;
40463 tw += this.editicon ? this.editicon.getWidth() : 0;
40465 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40467 this.combo.trigger.setStyle('left', '0px');
40469 if(this.list && this.listWidth === undefined){
40470 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40471 this.list.setWidth(lw);
40472 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40479 addItem: function(rec)
40481 var valueField = this.combo.valueField;
40482 var displayField = this.combo.displayField;
40483 if (this.items.indexOfKey(rec[valueField]) > -1) {
40484 //console.log("GOT " + rec.data.id);
40488 var x = new Roo.form.ComboBoxArray.Item({
40489 //id : rec[this.idField],
40491 displayField : displayField ,
40492 tipField : displayField ,
40496 this.items.add(rec[valueField],x);
40497 // add it before the element..
40498 this.updateHiddenEl();
40499 x.render(this.outerWrap, this.wrap.dom);
40500 // add the image handler..
40503 updateHiddenEl : function()
40506 if (!this.hiddenEl) {
40510 var idField = this.combo.valueField;
40512 this.items.each(function(f) {
40513 ar.push(f.data[idField]);
40516 this.hiddenEl.dom.value = ar.join(',');
40522 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40523 this.items.each(function(f) {
40526 this.el.dom.value = '';
40527 if (this.hiddenEl) {
40528 this.hiddenEl.dom.value = '';
40532 getValue: function()
40534 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40536 setValue: function(v) // not a valid action - must use addItems..
40543 if (this.store.isLocal && (typeof(v) == 'string')) {
40544 // then we can use the store to find the values..
40545 // comma seperated at present.. this needs to allow JSON based encoding..
40546 this.hiddenEl.value = v;
40548 Roo.each(v.split(','), function(k) {
40549 Roo.log("CHECK " + this.valueField + ',' + k);
40550 var li = this.store.query(this.valueField, k);
40555 add[this.valueField] = k;
40556 add[this.displayField] = li.item(0).data[this.displayField];
40562 if (typeof(v) == 'object') {
40563 // then let's assume it's an array of objects..
40564 Roo.each(v, function(l) {
40572 setFromData: function(v)
40574 // this recieves an object, if setValues is called.
40576 this.el.dom.value = v[this.displayField];
40577 this.hiddenEl.dom.value = v[this.valueField];
40578 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40581 var kv = v[this.valueField];
40582 var dv = v[this.displayField];
40583 kv = typeof(kv) != 'string' ? '' : kv;
40584 dv = typeof(dv) != 'string' ? '' : dv;
40587 var keys = kv.split(',');
40588 var display = dv.split(',');
40589 for (var i = 0 ; i < keys.length; i++) {
40592 add[this.valueField] = keys[i];
40593 add[this.displayField] = display[i];
40601 * Validates the combox array value
40602 * @return {Boolean} True if the value is valid, else false
40604 validate : function(){
40605 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40606 this.clearInvalid();
40612 validateValue : function(value){
40613 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40621 isDirty : function() {
40622 if(this.disabled) {
40627 var d = Roo.decode(String(this.originalValue));
40629 return String(this.getValue()) !== String(this.originalValue);
40632 var originalValue = [];
40634 for (var i = 0; i < d.length; i++){
40635 originalValue.push(d[i][this.valueField]);
40638 return String(this.getValue()) !== String(originalValue.join(','));
40647 * @class Roo.form.ComboBoxArray.Item
40648 * @extends Roo.BoxComponent
40649 * A selected item in the list
40650 * Fred [x] Brian [x] [Pick another |v]
40653 * Create a new item.
40654 * @param {Object} config Configuration options
40657 Roo.form.ComboBoxArray.Item = function(config) {
40658 config.id = Roo.id();
40659 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40662 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40665 displayField : false,
40669 defaultAutoCreate : {
40671 cls: 'x-cbarray-item',
40678 src : Roo.BLANK_IMAGE_URL ,
40686 onRender : function(ct, position)
40688 Roo.form.Field.superclass.onRender.call(this, ct, position);
40691 var cfg = this.getAutoCreate();
40692 this.el = ct.createChild(cfg, position);
40695 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40697 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40698 this.cb.renderer(this.data) :
40699 String.format('{0}',this.data[this.displayField]);
40702 this.el.child('div').dom.setAttribute('qtip',
40703 String.format('{0}',this.data[this.tipField])
40706 this.el.child('img').on('click', this.remove, this);
40710 remove : function()
40712 this.cb.items.remove(this);
40713 this.el.child('img').un('click', this.remove, this);
40715 this.cb.updateHiddenEl();
40717 this.cb.fireEvent('remove', this.cb, this);
40721 * Ext JS Library 1.1.1
40722 * Copyright(c) 2006-2007, Ext JS, LLC.
40724 * Originally Released Under LGPL - original licence link has changed is not relivant.
40727 * <script type="text/javascript">
40730 * @class Roo.form.Checkbox
40731 * @extends Roo.form.Field
40732 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40734 * Creates a new Checkbox
40735 * @param {Object} config Configuration options
40737 Roo.form.Checkbox = function(config){
40738 Roo.form.Checkbox.superclass.constructor.call(this, config);
40742 * Fires when the checkbox is checked or unchecked.
40743 * @param {Roo.form.Checkbox} this This checkbox
40744 * @param {Boolean} checked The new checked value
40750 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40752 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40754 focusClass : undefined,
40756 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40758 fieldClass: "x-form-field",
40760 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40764 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40765 * {tag: "input", type: "checkbox", autocomplete: "off"})
40767 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40769 * @cfg {String} boxLabel The text that appears beside the checkbox
40773 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40777 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40779 valueOff: '0', // value when not checked..
40781 actionMode : 'viewEl',
40784 itemCls : 'x-menu-check-item x-form-item',
40785 groupClass : 'x-menu-group-item',
40786 inputType : 'hidden',
40789 inSetChecked: false, // check that we are not calling self...
40791 inputElement: false, // real input element?
40792 basedOn: false, // ????
40794 isFormField: true, // not sure where this is needed!!!!
40796 onResize : function(){
40797 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40798 if(!this.boxLabel){
40799 this.el.alignTo(this.wrap, 'c-c');
40803 initEvents : function(){
40804 Roo.form.Checkbox.superclass.initEvents.call(this);
40805 this.el.on("click", this.onClick, this);
40806 this.el.on("change", this.onClick, this);
40810 getResizeEl : function(){
40814 getPositionEl : function(){
40819 onRender : function(ct, position){
40820 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40822 if(this.inputValue !== undefined){
40823 this.el.dom.value = this.inputValue;
40826 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40827 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40828 var viewEl = this.wrap.createChild({
40829 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40830 this.viewEl = viewEl;
40831 this.wrap.on('click', this.onClick, this);
40833 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40834 this.el.on('propertychange', this.setFromHidden, this); //ie
40839 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40840 // viewEl.on('click', this.onClick, this);
40842 //if(this.checked){
40843 this.setChecked(this.checked);
40845 //this.checked = this.el.dom;
40851 initValue : Roo.emptyFn,
40854 * Returns the checked state of the checkbox.
40855 * @return {Boolean} True if checked, else false
40857 getValue : function(){
40859 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40861 return this.valueOff;
40866 onClick : function(){
40867 this.setChecked(!this.checked);
40869 //if(this.el.dom.checked != this.checked){
40870 // this.setValue(this.el.dom.checked);
40875 * Sets the checked state of the checkbox.
40876 * On is always based on a string comparison between inputValue and the param.
40877 * @param {Boolean/String} value - the value to set
40878 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40880 setValue : function(v,suppressEvent){
40883 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40884 //if(this.el && this.el.dom){
40885 // this.el.dom.checked = this.checked;
40886 // this.el.dom.defaultChecked = this.checked;
40888 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40889 //this.fireEvent("check", this, this.checked);
40892 setChecked : function(state,suppressEvent)
40894 if (this.inSetChecked) {
40895 this.checked = state;
40901 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40903 this.checked = state;
40904 if(suppressEvent !== true){
40905 this.fireEvent('check', this, state);
40907 this.inSetChecked = true;
40908 this.el.dom.value = state ? this.inputValue : this.valueOff;
40909 this.inSetChecked = false;
40912 // handle setting of hidden value by some other method!!?!?
40913 setFromHidden: function()
40918 //console.log("SET FROM HIDDEN");
40919 //alert('setFrom hidden');
40920 this.setValue(this.el.dom.value);
40923 onDestroy : function()
40926 Roo.get(this.viewEl).remove();
40929 Roo.form.Checkbox.superclass.onDestroy.call(this);
40934 * Ext JS Library 1.1.1
40935 * Copyright(c) 2006-2007, Ext JS, LLC.
40937 * Originally Released Under LGPL - original licence link has changed is not relivant.
40940 * <script type="text/javascript">
40944 * @class Roo.form.Radio
40945 * @extends Roo.form.Checkbox
40946 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40947 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40949 * Creates a new Radio
40950 * @param {Object} config Configuration options
40952 Roo.form.Radio = function(){
40953 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40955 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40956 inputType: 'radio',
40959 * If this radio is part of a group, it will return the selected value
40962 getGroupValue : function(){
40963 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40967 onRender : function(ct, position){
40968 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40970 if(this.inputValue !== undefined){
40971 this.el.dom.value = this.inputValue;
40974 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40975 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40976 //var viewEl = this.wrap.createChild({
40977 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40978 //this.viewEl = viewEl;
40979 //this.wrap.on('click', this.onClick, this);
40981 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40982 //this.el.on('propertychange', this.setFromHidden, this); //ie
40987 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40988 // viewEl.on('click', this.onClick, this);
40991 this.el.dom.checked = 'checked' ;
40997 });//<script type="text/javascript">
41000 * Based Ext JS Library 1.1.1
41001 * Copyright(c) 2006-2007, Ext JS, LLC.
41007 * @class Roo.HtmlEditorCore
41008 * @extends Roo.Component
41009 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41011 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41014 Roo.HtmlEditorCore = function(config){
41017 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41020 * @event initialize
41021 * Fires when the editor is fully initialized (including the iframe)
41022 * @param {Roo.HtmlEditorCore} this
41027 * Fires when the editor is first receives the focus. Any insertion must wait
41028 * until after this event.
41029 * @param {Roo.HtmlEditorCore} this
41033 * @event beforesync
41034 * Fires before the textarea is updated with content from the editor iframe. Return false
41035 * to cancel the sync.
41036 * @param {Roo.HtmlEditorCore} this
41037 * @param {String} html
41041 * @event beforepush
41042 * Fires before the iframe editor is updated with content from the textarea. Return false
41043 * to cancel the push.
41044 * @param {Roo.HtmlEditorCore} this
41045 * @param {String} html
41050 * Fires when the textarea is updated with content from the editor iframe.
41051 * @param {Roo.HtmlEditorCore} this
41052 * @param {String} html
41057 * Fires when the iframe editor is updated with content from the textarea.
41058 * @param {Roo.HtmlEditorCore} this
41059 * @param {String} html
41064 * @event editorevent
41065 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41066 * @param {Roo.HtmlEditorCore} this
41074 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41078 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41084 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41089 * @cfg {Number} height (in pixels)
41093 * @cfg {Number} width (in pixels)
41098 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41101 stylesheets: false,
41106 // private properties
41107 validationEvent : false,
41109 initialized : false,
41111 sourceEditMode : false,
41112 onFocus : Roo.emptyFn,
41114 hideMode:'offsets',
41122 * Protected method that will not generally be called directly. It
41123 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41124 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41126 getDocMarkup : function(){
41129 Roo.log(this.stylesheets);
41131 // inherit styels from page...??
41132 if (this.stylesheets === false) {
41134 Roo.get(document.head).select('style').each(function(node) {
41135 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41138 Roo.get(document.head).select('link').each(function(node) {
41139 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41142 } else if (!this.stylesheets.length) {
41144 st = '<style type="text/css">' +
41145 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41148 Roo.each(this.stylesheets, function(s) {
41149 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
41154 st += '<style type="text/css">' +
41155 'IMG { cursor: pointer } ' +
41159 return '<html><head>' + st +
41160 //<style type="text/css">' +
41161 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41163 ' </head><body class="roo-htmleditor-body"></body></html>';
41167 onRender : function(ct, position)
41170 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41171 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41174 this.el.dom.style.border = '0 none';
41175 this.el.dom.setAttribute('tabIndex', -1);
41176 this.el.addClass('x-hidden hide');
41180 if(Roo.isIE){ // fix IE 1px bogus margin
41181 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41185 this.frameId = Roo.id();
41189 var iframe = this.owner.wrap.createChild({
41191 cls: 'form-control', // bootstrap..
41193 name: this.frameId,
41194 frameBorder : 'no',
41195 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41200 this.iframe = iframe.dom;
41202 this.assignDocWin();
41204 this.doc.designMode = 'on';
41207 this.doc.write(this.getDocMarkup());
41211 var task = { // must defer to wait for browser to be ready
41213 //console.log("run task?" + this.doc.readyState);
41214 this.assignDocWin();
41215 if(this.doc.body || this.doc.readyState == 'complete'){
41217 this.doc.designMode="on";
41221 Roo.TaskMgr.stop(task);
41222 this.initEditor.defer(10, this);
41229 Roo.TaskMgr.start(task);
41236 onResize : function(w, h)
41238 Roo.log('resize: ' +w + ',' + h );
41239 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41243 if(typeof w == 'number'){
41245 this.iframe.style.width = w + 'px';
41247 if(typeof h == 'number'){
41249 this.iframe.style.height = h + 'px';
41251 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41258 * Toggles the editor between standard and source edit mode.
41259 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41261 toggleSourceEdit : function(sourceEditMode){
41263 this.sourceEditMode = sourceEditMode === true;
41265 if(this.sourceEditMode){
41267 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41270 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41271 //this.iframe.className = '';
41274 //this.setSize(this.owner.wrap.getSize());
41275 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41282 * Protected method that will not generally be called directly. If you need/want
41283 * custom HTML cleanup, this is the method you should override.
41284 * @param {String} html The HTML to be cleaned
41285 * return {String} The cleaned HTML
41287 cleanHtml : function(html){
41288 html = String(html);
41289 if(html.length > 5){
41290 if(Roo.isSafari){ // strip safari nonsense
41291 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41294 if(html == ' '){
41301 * HTML Editor -> Textarea
41302 * Protected method that will not generally be called directly. Syncs the contents
41303 * of the editor iframe with the textarea.
41305 syncValue : function(){
41306 if(this.initialized){
41307 var bd = (this.doc.body || this.doc.documentElement);
41308 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41309 var html = bd.innerHTML;
41311 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41312 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41314 html = '<div style="'+m[0]+'">' + html + '</div>';
41317 html = this.cleanHtml(html);
41318 // fix up the special chars.. normaly like back quotes in word...
41319 // however we do not want to do this with chinese..
41320 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41321 var cc = b.charCodeAt();
41323 (cc >= 0x4E00 && cc < 0xA000 ) ||
41324 (cc >= 0x3400 && cc < 0x4E00 ) ||
41325 (cc >= 0xf900 && cc < 0xfb00 )
41331 if(this.owner.fireEvent('beforesync', this, html) !== false){
41332 this.el.dom.value = html;
41333 this.owner.fireEvent('sync', this, html);
41339 * Protected method that will not generally be called directly. Pushes the value of the textarea
41340 * into the iframe editor.
41342 pushValue : function(){
41343 if(this.initialized){
41344 var v = this.el.dom.value.trim();
41346 // if(v.length < 1){
41350 if(this.owner.fireEvent('beforepush', this, v) !== false){
41351 var d = (this.doc.body || this.doc.documentElement);
41353 this.cleanUpPaste();
41354 this.el.dom.value = d.innerHTML;
41355 this.owner.fireEvent('push', this, v);
41361 deferFocus : function(){
41362 this.focus.defer(10, this);
41366 focus : function(){
41367 if(this.win && !this.sourceEditMode){
41374 assignDocWin: function()
41376 var iframe = this.iframe;
41379 this.doc = iframe.contentWindow.document;
41380 this.win = iframe.contentWindow;
41382 if (!Roo.get(this.frameId)) {
41385 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41386 this.win = Roo.get(this.frameId).dom.contentWindow;
41391 initEditor : function(){
41392 //console.log("INIT EDITOR");
41393 this.assignDocWin();
41397 this.doc.designMode="on";
41399 this.doc.write(this.getDocMarkup());
41402 var dbody = (this.doc.body || this.doc.documentElement);
41403 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41404 // this copies styles from the containing element into thsi one..
41405 // not sure why we need all of this..
41406 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41408 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41409 //ss['background-attachment'] = 'fixed'; // w3c
41410 dbody.bgProperties = 'fixed'; // ie
41411 //Roo.DomHelper.applyStyles(dbody, ss);
41412 Roo.EventManager.on(this.doc, {
41413 //'mousedown': this.onEditorEvent,
41414 'mouseup': this.onEditorEvent,
41415 'dblclick': this.onEditorEvent,
41416 'click': this.onEditorEvent,
41417 'keyup': this.onEditorEvent,
41422 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41424 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41425 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41427 this.initialized = true;
41429 this.owner.fireEvent('initialize', this);
41434 onDestroy : function(){
41440 //for (var i =0; i < this.toolbars.length;i++) {
41441 // // fixme - ask toolbars for heights?
41442 // this.toolbars[i].onDestroy();
41445 //this.wrap.dom.innerHTML = '';
41446 //this.wrap.remove();
41451 onFirstFocus : function(){
41453 this.assignDocWin();
41456 this.activated = true;
41459 if(Roo.isGecko){ // prevent silly gecko errors
41461 var s = this.win.getSelection();
41462 if(!s.focusNode || s.focusNode.nodeType != 3){
41463 var r = s.getRangeAt(0);
41464 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41469 this.execCmd('useCSS', true);
41470 this.execCmd('styleWithCSS', false);
41473 this.owner.fireEvent('activate', this);
41477 adjustFont: function(btn){
41478 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41479 //if(Roo.isSafari){ // safari
41482 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41483 if(Roo.isSafari){ // safari
41484 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41485 v = (v < 10) ? 10 : v;
41486 v = (v > 48) ? 48 : v;
41487 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41492 v = Math.max(1, v+adjust);
41494 this.execCmd('FontSize', v );
41497 onEditorEvent : function(e){
41498 this.owner.fireEvent('editorevent', this, e);
41499 // this.updateToolbar();
41500 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41503 insertTag : function(tg)
41505 // could be a bit smarter... -> wrap the current selected tRoo..
41506 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41508 range = this.createRange(this.getSelection());
41509 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41510 wrappingNode.appendChild(range.extractContents());
41511 range.insertNode(wrappingNode);
41518 this.execCmd("formatblock", tg);
41522 insertText : function(txt)
41526 var range = this.createRange();
41527 range.deleteContents();
41528 //alert(Sender.getAttribute('label'));
41530 range.insertNode(this.doc.createTextNode(txt));
41536 * Executes a Midas editor command on the editor document and performs necessary focus and
41537 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41538 * @param {String} cmd The Midas command
41539 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41541 relayCmd : function(cmd, value){
41543 this.execCmd(cmd, value);
41544 this.owner.fireEvent('editorevent', this);
41545 //this.updateToolbar();
41546 this.owner.deferFocus();
41550 * Executes a Midas editor command directly on the editor document.
41551 * For visual commands, you should use {@link #relayCmd} instead.
41552 * <b>This should only be called after the editor is initialized.</b>
41553 * @param {String} cmd The Midas command
41554 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41556 execCmd : function(cmd, value){
41557 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41564 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41566 * @param {String} text | dom node..
41568 insertAtCursor : function(text)
41573 if(!this.activated){
41579 var r = this.doc.selection.createRange();
41590 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41594 // from jquery ui (MIT licenced)
41596 var win = this.win;
41598 if (win.getSelection && win.getSelection().getRangeAt) {
41599 range = win.getSelection().getRangeAt(0);
41600 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41601 range.insertNode(node);
41602 } else if (win.document.selection && win.document.selection.createRange) {
41603 // no firefox support
41604 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41605 win.document.selection.createRange().pasteHTML(txt);
41607 // no firefox support
41608 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41609 this.execCmd('InsertHTML', txt);
41618 mozKeyPress : function(e){
41620 var c = e.getCharCode(), cmd;
41623 c = String.fromCharCode(c).toLowerCase();
41637 this.cleanUpPaste.defer(100, this);
41645 e.preventDefault();
41653 fixKeys : function(){ // load time branching for fastest keydown performance
41655 return function(e){
41656 var k = e.getKey(), r;
41659 r = this.doc.selection.createRange();
41662 r.pasteHTML('    ');
41669 r = this.doc.selection.createRange();
41671 var target = r.parentElement();
41672 if(!target || target.tagName.toLowerCase() != 'li'){
41674 r.pasteHTML('<br />');
41680 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41681 this.cleanUpPaste.defer(100, this);
41687 }else if(Roo.isOpera){
41688 return function(e){
41689 var k = e.getKey();
41693 this.execCmd('InsertHTML','    ');
41696 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41697 this.cleanUpPaste.defer(100, this);
41702 }else if(Roo.isSafari){
41703 return function(e){
41704 var k = e.getKey();
41708 this.execCmd('InsertText','\t');
41712 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41713 this.cleanUpPaste.defer(100, this);
41721 getAllAncestors: function()
41723 var p = this.getSelectedNode();
41726 a.push(p); // push blank onto stack..
41727 p = this.getParentElement();
41731 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41735 a.push(this.doc.body);
41739 lastSelNode : false,
41742 getSelection : function()
41744 this.assignDocWin();
41745 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41748 getSelectedNode: function()
41750 // this may only work on Gecko!!!
41752 // should we cache this!!!!
41757 var range = this.createRange(this.getSelection()).cloneRange();
41760 var parent = range.parentElement();
41762 var testRange = range.duplicate();
41763 testRange.moveToElementText(parent);
41764 if (testRange.inRange(range)) {
41767 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41770 parent = parent.parentElement;
41775 // is ancestor a text element.
41776 var ac = range.commonAncestorContainer;
41777 if (ac.nodeType == 3) {
41778 ac = ac.parentNode;
41781 var ar = ac.childNodes;
41784 var other_nodes = [];
41785 var has_other_nodes = false;
41786 for (var i=0;i<ar.length;i++) {
41787 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41790 // fullly contained node.
41792 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41797 // probably selected..
41798 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41799 other_nodes.push(ar[i]);
41803 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41808 has_other_nodes = true;
41810 if (!nodes.length && other_nodes.length) {
41811 nodes= other_nodes;
41813 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41819 createRange: function(sel)
41821 // this has strange effects when using with
41822 // top toolbar - not sure if it's a great idea.
41823 //this.editor.contentWindow.focus();
41824 if (typeof sel != "undefined") {
41826 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41828 return this.doc.createRange();
41831 return this.doc.createRange();
41834 getParentElement: function()
41837 this.assignDocWin();
41838 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41840 var range = this.createRange(sel);
41843 var p = range.commonAncestorContainer;
41844 while (p.nodeType == 3) { // text node
41855 * Range intersection.. the hard stuff...
41859 * [ -- selected range --- ]
41863 * if end is before start or hits it. fail.
41864 * if start is after end or hits it fail.
41866 * if either hits (but other is outside. - then it's not
41872 // @see http://www.thismuchiknow.co.uk/?p=64.
41873 rangeIntersectsNode : function(range, node)
41875 var nodeRange = node.ownerDocument.createRange();
41877 nodeRange.selectNode(node);
41879 nodeRange.selectNodeContents(node);
41882 var rangeStartRange = range.cloneRange();
41883 rangeStartRange.collapse(true);
41885 var rangeEndRange = range.cloneRange();
41886 rangeEndRange.collapse(false);
41888 var nodeStartRange = nodeRange.cloneRange();
41889 nodeStartRange.collapse(true);
41891 var nodeEndRange = nodeRange.cloneRange();
41892 nodeEndRange.collapse(false);
41894 return rangeStartRange.compareBoundaryPoints(
41895 Range.START_TO_START, nodeEndRange) == -1 &&
41896 rangeEndRange.compareBoundaryPoints(
41897 Range.START_TO_START, nodeStartRange) == 1;
41901 rangeCompareNode : function(range, node)
41903 var nodeRange = node.ownerDocument.createRange();
41905 nodeRange.selectNode(node);
41907 nodeRange.selectNodeContents(node);
41911 range.collapse(true);
41913 nodeRange.collapse(true);
41915 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41916 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41918 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41920 var nodeIsBefore = ss == 1;
41921 var nodeIsAfter = ee == -1;
41923 if (nodeIsBefore && nodeIsAfter)
41925 if (!nodeIsBefore && nodeIsAfter)
41926 return 1; //right trailed.
41928 if (nodeIsBefore && !nodeIsAfter)
41929 return 2; // left trailed.
41934 // private? - in a new class?
41935 cleanUpPaste : function()
41937 // cleans up the whole document..
41938 Roo.log('cleanuppaste');
41940 this.cleanUpChildren(this.doc.body);
41941 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41942 if (clean != this.doc.body.innerHTML) {
41943 this.doc.body.innerHTML = clean;
41948 cleanWordChars : function(input) {// change the chars to hex code
41949 var he = Roo.HtmlEditorCore;
41951 var output = input;
41952 Roo.each(he.swapCodes, function(sw) {
41953 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41955 output = output.replace(swapper, sw[1]);
41962 cleanUpChildren : function (n)
41964 if (!n.childNodes.length) {
41967 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41968 this.cleanUpChild(n.childNodes[i]);
41975 cleanUpChild : function (node)
41978 //console.log(node);
41979 if (node.nodeName == "#text") {
41980 // clean up silly Windows -- stuff?
41983 if (node.nodeName == "#comment") {
41984 node.parentNode.removeChild(node);
41985 // clean up silly Windows -- stuff?
41989 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
41991 node.parentNode.removeChild(node);
41996 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
41998 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41999 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42001 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42002 // remove_keep_children = true;
42005 if (remove_keep_children) {
42006 this.cleanUpChildren(node);
42007 // inserts everything just before this node...
42008 while (node.childNodes.length) {
42009 var cn = node.childNodes[0];
42010 node.removeChild(cn);
42011 node.parentNode.insertBefore(cn, node);
42013 node.parentNode.removeChild(node);
42017 if (!node.attributes || !node.attributes.length) {
42018 this.cleanUpChildren(node);
42022 function cleanAttr(n,v)
42025 if (v.match(/^\./) || v.match(/^\//)) {
42028 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42031 if (v.match(/^#/)) {
42034 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42035 node.removeAttribute(n);
42039 function cleanStyle(n,v)
42041 if (v.match(/expression/)) { //XSS?? should we even bother..
42042 node.removeAttribute(n);
42045 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
42046 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
42049 var parts = v.split(/;/);
42052 Roo.each(parts, function(p) {
42053 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42057 var l = p.split(':').shift().replace(/\s+/g,'');
42058 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42060 if ( cblack.indexOf(l) > -1) {
42061 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42062 //node.removeAttribute(n);
42066 // only allow 'c whitelisted system attributes'
42067 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42068 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42069 //node.removeAttribute(n);
42079 if (clean.length) {
42080 node.setAttribute(n, clean.join(';'));
42082 node.removeAttribute(n);
42088 for (var i = node.attributes.length-1; i > -1 ; i--) {
42089 var a = node.attributes[i];
42092 if (a.name.toLowerCase().substr(0,2)=='on') {
42093 node.removeAttribute(a.name);
42096 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42097 node.removeAttribute(a.name);
42100 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42101 cleanAttr(a.name,a.value); // fixme..
42104 if (a.name == 'style') {
42105 cleanStyle(a.name,a.value);
42108 /// clean up MS crap..
42109 // tecnically this should be a list of valid class'es..
42112 if (a.name == 'class') {
42113 if (a.value.match(/^Mso/)) {
42114 node.className = '';
42117 if (a.value.match(/body/)) {
42118 node.className = '';
42129 this.cleanUpChildren(node);
42134 * Clean up MS wordisms...
42136 cleanWord : function(node)
42139 var cleanWordChildren = function()
42141 if (!node.childNodes.length) {
42144 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42145 _t.cleanWord(node.childNodes[i]);
42151 this.cleanWord(this.doc.body);
42154 if (node.nodeName == "#text") {
42155 // clean up silly Windows -- stuff?
42158 if (node.nodeName == "#comment") {
42159 node.parentNode.removeChild(node);
42160 // clean up silly Windows -- stuff?
42164 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42165 node.parentNode.removeChild(node);
42169 // remove - but keep children..
42170 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42171 while (node.childNodes.length) {
42172 var cn = node.childNodes[0];
42173 node.removeChild(cn);
42174 node.parentNode.insertBefore(cn, node);
42176 node.parentNode.removeChild(node);
42177 cleanWordChildren();
42181 if (node.className.length) {
42183 var cn = node.className.split(/\W+/);
42185 Roo.each(cn, function(cls) {
42186 if (cls.match(/Mso[a-zA-Z]+/)) {
42191 node.className = cna.length ? cna.join(' ') : '';
42193 node.removeAttribute("class");
42197 if (node.hasAttribute("lang")) {
42198 node.removeAttribute("lang");
42201 if (node.hasAttribute("style")) {
42203 var styles = node.getAttribute("style").split(";");
42205 Roo.each(styles, function(s) {
42206 if (!s.match(/:/)) {
42209 var kv = s.split(":");
42210 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42213 // what ever is left... we allow.
42216 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42217 if (!nstyle.length) {
42218 node.removeAttribute('style');
42222 cleanWordChildren();
42226 domToHTML : function(currentElement, depth, nopadtext) {
42228 depth = depth || 0;
42229 nopadtext = nopadtext || false;
42231 if (!currentElement) {
42232 return this.domToHTML(this.doc.body);
42235 //Roo.log(currentElement);
42237 var allText = false;
42238 var nodeName = currentElement.nodeName;
42239 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42241 if (nodeName == '#text') {
42242 return currentElement.nodeValue;
42247 if (nodeName != 'BODY') {
42250 // Prints the node tagName, such as <A>, <IMG>, etc
42253 for(i = 0; i < currentElement.attributes.length;i++) {
42255 var aname = currentElement.attributes.item(i).name;
42256 if (!currentElement.attributes.item(i).value.length) {
42259 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42262 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42271 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42274 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42279 // Traverse the tree
42281 var currentElementChild = currentElement.childNodes.item(i);
42282 var allText = true;
42283 var innerHTML = '';
42285 while (currentElementChild) {
42286 // Formatting code (indent the tree so it looks nice on the screen)
42287 var nopad = nopadtext;
42288 if (lastnode == 'SPAN') {
42292 if (currentElementChild.nodeName == '#text') {
42293 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42294 if (!nopad && toadd.length > 80) {
42295 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42297 innerHTML += toadd;
42300 currentElementChild = currentElement.childNodes.item(i);
42306 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42308 // Recursively traverse the tree structure of the child node
42309 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42310 lastnode = currentElementChild.nodeName;
42312 currentElementChild=currentElement.childNodes.item(i);
42318 // The remaining code is mostly for formatting the tree
42319 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42324 ret+= "</"+tagName+">";
42330 // hide stuff that is not compatible
42344 * @event specialkey
42348 * @cfg {String} fieldClass @hide
42351 * @cfg {String} focusClass @hide
42354 * @cfg {String} autoCreate @hide
42357 * @cfg {String} inputType @hide
42360 * @cfg {String} invalidClass @hide
42363 * @cfg {String} invalidText @hide
42366 * @cfg {String} msgFx @hide
42369 * @cfg {String} validateOnBlur @hide
42373 Roo.HtmlEditorCore.white = [
42374 'area', 'br', 'img', 'input', 'hr', 'wbr',
42376 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42377 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42378 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42379 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42380 'table', 'ul', 'xmp',
42382 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42385 'dir', 'menu', 'ol', 'ul', 'dl',
42391 Roo.HtmlEditorCore.black = [
42392 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42394 'base', 'basefont', 'bgsound', 'blink', 'body',
42395 'frame', 'frameset', 'head', 'html', 'ilayer',
42396 'iframe', 'layer', 'link', 'meta', 'object',
42397 'script', 'style' ,'title', 'xml' // clean later..
42399 Roo.HtmlEditorCore.clean = [
42400 'script', 'style', 'title', 'xml'
42402 Roo.HtmlEditorCore.remove = [
42407 Roo.HtmlEditorCore.ablack = [
42411 Roo.HtmlEditorCore.aclean = [
42412 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42416 Roo.HtmlEditorCore.pwhite= [
42417 'http', 'https', 'mailto'
42420 // white listed style attributes.
42421 Roo.HtmlEditorCore.cwhite= [
42422 // 'text-align', /// default is to allow most things..
42428 // black listed style attributes.
42429 Roo.HtmlEditorCore.cblack= [
42430 // 'font-size' -- this can be set by the project
42434 Roo.HtmlEditorCore.swapCodes =[
42445 //<script type="text/javascript">
42448 * Ext JS Library 1.1.1
42449 * Copyright(c) 2006-2007, Ext JS, LLC.
42455 Roo.form.HtmlEditor = function(config){
42459 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42461 if (!this.toolbars) {
42462 this.toolbars = [];
42464 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42470 * @class Roo.form.HtmlEditor
42471 * @extends Roo.form.Field
42472 * Provides a lightweight HTML Editor component.
42474 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42476 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42477 * supported by this editor.</b><br/><br/>
42478 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42479 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42481 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42483 * @cfg {Boolean} clearUp
42487 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42492 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42497 * @cfg {Number} height (in pixels)
42501 * @cfg {Number} width (in pixels)
42506 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42509 stylesheets: false,
42514 // private properties
42515 validationEvent : false,
42517 initialized : false,
42520 onFocus : Roo.emptyFn,
42522 hideMode:'offsets',
42524 defaultAutoCreate : { // modified by initCompnoent..
42526 style:"width:500px;height:300px;",
42527 autocomplete: "off"
42531 initComponent : function(){
42534 * @event initialize
42535 * Fires when the editor is fully initialized (including the iframe)
42536 * @param {HtmlEditor} this
42541 * Fires when the editor is first receives the focus. Any insertion must wait
42542 * until after this event.
42543 * @param {HtmlEditor} this
42547 * @event beforesync
42548 * Fires before the textarea is updated with content from the editor iframe. Return false
42549 * to cancel the sync.
42550 * @param {HtmlEditor} this
42551 * @param {String} html
42555 * @event beforepush
42556 * Fires before the iframe editor is updated with content from the textarea. Return false
42557 * to cancel the push.
42558 * @param {HtmlEditor} this
42559 * @param {String} html
42564 * Fires when the textarea is updated with content from the editor iframe.
42565 * @param {HtmlEditor} this
42566 * @param {String} html
42571 * Fires when the iframe editor is updated with content from the textarea.
42572 * @param {HtmlEditor} this
42573 * @param {String} html
42577 * @event editmodechange
42578 * Fires when the editor switches edit modes
42579 * @param {HtmlEditor} this
42580 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42582 editmodechange: true,
42584 * @event editorevent
42585 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42586 * @param {HtmlEditor} this
42590 * @event firstfocus
42591 * Fires when on first focus - needed by toolbars..
42592 * @param {HtmlEditor} this
42597 * Auto save the htmlEditor value as a file into Events
42598 * @param {HtmlEditor} this
42602 * @event savedpreview
42603 * preview the saved version of htmlEditor
42604 * @param {HtmlEditor} this
42608 this.defaultAutoCreate = {
42610 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42611 autocomplete: "off"
42616 * Protected method that will not generally be called directly. It
42617 * is called when the editor creates its toolbar. Override this method if you need to
42618 * add custom toolbar buttons.
42619 * @param {HtmlEditor} editor
42621 createToolbar : function(editor){
42622 Roo.log("create toolbars");
42623 if (!editor.toolbars || !editor.toolbars.length) {
42624 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42627 for (var i =0 ; i < editor.toolbars.length;i++) {
42628 editor.toolbars[i] = Roo.factory(
42629 typeof(editor.toolbars[i]) == 'string' ?
42630 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42631 Roo.form.HtmlEditor);
42632 editor.toolbars[i].init(editor);
42640 onRender : function(ct, position)
42643 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
42645 this.wrap = this.el.wrap({
42646 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
42649 this.editorcore.onRender(ct, position);
42651 if (this.resizable) {
42652 this.resizeEl = new Roo.Resizable(this.wrap, {
42656 minHeight : this.height,
42657 height: this.height,
42658 handles : this.resizable,
42661 resize : function(r, w, h) {
42662 _t.onResize(w,h); // -something
42668 this.createToolbar(this);
42672 this.setSize(this.wrap.getSize());
42674 if (this.resizeEl) {
42675 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
42676 // should trigger onReize..
42679 // if(this.autosave && this.w){
42680 // this.autoSaveFn = setInterval(this.autosave, 1000);
42685 onResize : function(w, h)
42687 //Roo.log('resize: ' +w + ',' + h );
42688 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
42693 if(typeof w == 'number'){
42694 var aw = w - this.wrap.getFrameWidth('lr');
42695 this.el.setWidth(this.adjustWidth('textarea', aw));
42698 if(typeof h == 'number'){
42700 for (var i =0; i < this.toolbars.length;i++) {
42701 // fixme - ask toolbars for heights?
42702 tbh += this.toolbars[i].tb.el.getHeight();
42703 if (this.toolbars[i].footer) {
42704 tbh += this.toolbars[i].footer.el.getHeight();
42711 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
42712 ah -= 5; // knock a few pixes off for look..
42713 this.el.setHeight(this.adjustWidth('textarea', ah));
42717 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
42718 this.editorcore.onResize(ew,eh);
42723 * Toggles the editor between standard and source edit mode.
42724 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42726 toggleSourceEdit : function(sourceEditMode)
42728 this.editorcore.toggleSourceEdit(sourceEditMode);
42730 if(this.editorcore.sourceEditMode){
42731 Roo.log('editor - showing textarea');
42734 // Roo.log(this.syncValue());
42735 this.editorcore.syncValue();
42736 this.el.removeClass('x-hidden');
42737 this.el.dom.removeAttribute('tabIndex');
42740 Roo.log('editor - hiding textarea');
42742 // Roo.log(this.pushValue());
42743 this.editorcore.pushValue();
42745 this.el.addClass('x-hidden');
42746 this.el.dom.setAttribute('tabIndex', -1);
42747 //this.deferFocus();
42750 this.setSize(this.wrap.getSize());
42751 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
42754 // private (for BoxComponent)
42755 adjustSize : Roo.BoxComponent.prototype.adjustSize,
42757 // private (for BoxComponent)
42758 getResizeEl : function(){
42762 // private (for BoxComponent)
42763 getPositionEl : function(){
42768 initEvents : function(){
42769 this.originalValue = this.getValue();
42773 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42776 markInvalid : Roo.emptyFn,
42778 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42781 clearInvalid : Roo.emptyFn,
42783 setValue : function(v){
42784 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
42785 this.editorcore.pushValue();
42790 deferFocus : function(){
42791 this.focus.defer(10, this);
42795 focus : function(){
42796 this.editorcore.focus();
42802 onDestroy : function(){
42808 for (var i =0; i < this.toolbars.length;i++) {
42809 // fixme - ask toolbars for heights?
42810 this.toolbars[i].onDestroy();
42813 this.wrap.dom.innerHTML = '';
42814 this.wrap.remove();
42819 onFirstFocus : function(){
42820 //Roo.log("onFirstFocus");
42821 this.editorcore.onFirstFocus();
42822 for (var i =0; i < this.toolbars.length;i++) {
42823 this.toolbars[i].onFirstFocus();
42829 syncValue : function()
42831 this.editorcore.syncValue();
42834 pushValue : function()
42836 this.editorcore.pushValue();
42840 // hide stuff that is not compatible
42854 * @event specialkey
42858 * @cfg {String} fieldClass @hide
42861 * @cfg {String} focusClass @hide
42864 * @cfg {String} autoCreate @hide
42867 * @cfg {String} inputType @hide
42870 * @cfg {String} invalidClass @hide
42873 * @cfg {String} invalidText @hide
42876 * @cfg {String} msgFx @hide
42879 * @cfg {String} validateOnBlur @hide
42883 // <script type="text/javascript">
42886 * Ext JS Library 1.1.1
42887 * Copyright(c) 2006-2007, Ext JS, LLC.
42893 * @class Roo.form.HtmlEditorToolbar1
42898 new Roo.form.HtmlEditor({
42901 new Roo.form.HtmlEditorToolbar1({
42902 disable : { fonts: 1 , format: 1, ..., ... , ...],
42908 * @cfg {Object} disable List of elements to disable..
42909 * @cfg {Array} btns List of additional buttons.
42913 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
42916 Roo.form.HtmlEditor.ToolbarStandard = function(config)
42919 Roo.apply(this, config);
42921 // default disabled, based on 'good practice'..
42922 this.disable = this.disable || {};
42923 Roo.applyIf(this.disable, {
42926 specialElements : true
42930 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42931 // dont call parent... till later.
42934 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
42941 editorcore : false,
42943 * @cfg {Object} disable List of toolbar elements to disable
42950 * @cfg {String} createLinkText The default text for the create link prompt
42952 createLinkText : 'Please enter the URL for the link:',
42954 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
42956 defaultLinkValue : 'http:/'+'/',
42960 * @cfg {Array} fontFamilies An array of available font families
42978 // "á" , ?? a acute?
42983 "°" // , // degrees
42985 // "é" , // e ecute
42986 // "ú" , // u ecute?
42989 specialElements : [
42991 text: "Insert Table",
42994 ihtml : '<table><tr><td>Cell</td></tr></table>'
42998 text: "Insert Image",
43001 ihtml : '<img src="about:blank"/>'
43010 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43011 "input:submit", "input:button", "select", "textarea", "label" ],
43014 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43016 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43024 * @cfg {String} defaultFont default font to use.
43026 defaultFont: 'tahoma',
43028 fontSelect : false,
43031 formatCombo : false,
43033 init : function(editor)
43035 this.editor = editor;
43036 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43037 var editorcore = this.editorcore;
43041 var fid = editorcore.frameId;
43043 function btn(id, toggle, handler){
43044 var xid = fid + '-'+ id ;
43048 cls : 'x-btn-icon x-edit-'+id,
43049 enableToggle:toggle !== false,
43050 scope: _t, // was editor...
43051 handler:handler||_t.relayBtnCmd,
43052 clickEvent:'mousedown',
43053 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43060 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43062 // stop form submits
43063 tb.el.on('click', function(e){
43064 e.preventDefault(); // what does this do?
43067 if(!this.disable.font) { // && !Roo.isSafari){
43068 /* why no safari for fonts
43069 editor.fontSelect = tb.el.createChild({
43072 cls:'x-font-select',
43073 html: this.createFontOptions()
43076 editor.fontSelect.on('change', function(){
43077 var font = editor.fontSelect.dom.value;
43078 editor.relayCmd('fontname', font);
43079 editor.deferFocus();
43083 editor.fontSelect.dom,
43089 if(!this.disable.formats){
43090 this.formatCombo = new Roo.form.ComboBox({
43091 store: new Roo.data.SimpleStore({
43094 data : this.formats // from states.js
43098 //autoCreate : {tag: "div", size: "20"},
43099 displayField:'tag',
43103 triggerAction: 'all',
43104 emptyText:'Add tag',
43105 selectOnFocus:true,
43108 'select': function(c, r, i) {
43109 editorcore.insertTag(r.get('tag'));
43115 tb.addField(this.formatCombo);
43119 if(!this.disable.format){
43126 if(!this.disable.fontSize){
43131 btn('increasefontsize', false, editorcore.adjustFont),
43132 btn('decreasefontsize', false, editorcore.adjustFont)
43137 if(!this.disable.colors){
43140 id:editorcore.frameId +'-forecolor',
43141 cls:'x-btn-icon x-edit-forecolor',
43142 clickEvent:'mousedown',
43143 tooltip: this.buttonTips['forecolor'] || undefined,
43145 menu : new Roo.menu.ColorMenu({
43146 allowReselect: true,
43147 focus: Roo.emptyFn,
43150 selectHandler: function(cp, color){
43151 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43152 editor.deferFocus();
43155 clickEvent:'mousedown'
43158 id:editorcore.frameId +'backcolor',
43159 cls:'x-btn-icon x-edit-backcolor',
43160 clickEvent:'mousedown',
43161 tooltip: this.buttonTips['backcolor'] || undefined,
43163 menu : new Roo.menu.ColorMenu({
43164 focus: Roo.emptyFn,
43167 allowReselect: true,
43168 selectHandler: function(cp, color){
43170 editorcore.execCmd('useCSS', false);
43171 editorcore.execCmd('hilitecolor', color);
43172 editorcore.execCmd('useCSS', true);
43173 editor.deferFocus();
43175 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43176 Roo.isSafari || Roo.isIE ? '#'+color : color);
43177 editor.deferFocus();
43181 clickEvent:'mousedown'
43186 // now add all the items...
43189 if(!this.disable.alignments){
43192 btn('justifyleft'),
43193 btn('justifycenter'),
43194 btn('justifyright')
43198 //if(!Roo.isSafari){
43199 if(!this.disable.links){
43202 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43206 if(!this.disable.lists){
43209 btn('insertorderedlist'),
43210 btn('insertunorderedlist')
43213 if(!this.disable.sourceEdit){
43216 btn('sourceedit', true, function(btn){
43218 this.toggleSourceEdit(btn.pressed);
43225 // special menu.. - needs to be tidied up..
43226 if (!this.disable.special) {
43229 cls: 'x-edit-none',
43235 for (var i =0; i < this.specialChars.length; i++) {
43236 smenu.menu.items.push({
43238 html: this.specialChars[i],
43239 handler: function(a,b) {
43240 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43241 //editor.insertAtCursor(a.html);
43255 if (!this.disable.cleanStyles) {
43257 cls: 'x-btn-icon x-btn-clear',
43263 for (var i =0; i < this.cleanStyles.length; i++) {
43264 cmenu.menu.items.push({
43265 actiontype : this.cleanStyles[i],
43266 html: 'Remove ' + this.cleanStyles[i],
43267 handler: function(a,b) {
43270 var c = Roo.get(editorcore.doc.body);
43271 c.select('[style]').each(function(s) {
43272 s.dom.style.removeProperty(a.actiontype);
43274 editorcore.syncValue();
43279 cmenu.menu.items.push({
43280 actiontype : 'word',
43281 html: 'Remove MS Word Formating',
43282 handler: function(a,b) {
43283 editorcore.cleanWord();
43284 editorcore.syncValue();
43289 cmenu.menu.items.push({
43290 actiontype : 'all',
43291 html: 'Remove All Styles',
43292 handler: function(a,b) {
43294 var c = Roo.get(editorcore.doc.body);
43295 c.select('[style]').each(function(s) {
43296 s.dom.removeAttribute('style');
43298 editorcore.syncValue();
43302 cmenu.menu.items.push({
43303 actiontype : 'word',
43304 html: 'Tidy HTML Source',
43305 handler: function(a,b) {
43306 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43307 editorcore.syncValue();
43316 if (!this.disable.specialElements) {
43319 cls: 'x-edit-none',
43324 for (var i =0; i < this.specialElements.length; i++) {
43325 semenu.menu.items.push(
43327 handler: function(a,b) {
43328 editor.insertAtCursor(this.ihtml);
43330 }, this.specialElements[i])
43342 for(var i =0; i< this.btns.length;i++) {
43343 var b = Roo.factory(this.btns[i],Roo.form);
43344 b.cls = 'x-edit-none';
43345 b.scope = editorcore;
43353 // disable everything...
43355 this.tb.items.each(function(item){
43356 if(item.id != editorcore.frameId+ '-sourceedit'){
43360 this.rendered = true;
43362 // the all the btns;
43363 editor.on('editorevent', this.updateToolbar, this);
43364 // other toolbars need to implement this..
43365 //editor.on('editmodechange', this.updateToolbar, this);
43369 relayBtnCmd : function(btn) {
43370 this.editorcore.relayCmd(btn.cmd);
43372 // private used internally
43373 createLink : function(){
43374 Roo.log("create link?");
43375 var url = prompt(this.createLinkText, this.defaultLinkValue);
43376 if(url && url != 'http:/'+'/'){
43377 this.editorcore.relayCmd('createlink', url);
43383 * Protected method that will not generally be called directly. It triggers
43384 * a toolbar update by reading the markup state of the current selection in the editor.
43386 updateToolbar: function(){
43388 if(!this.editorcore.activated){
43389 this.editor.onFirstFocus();
43393 var btns = this.tb.items.map,
43394 doc = this.editorcore.doc,
43395 frameId = this.editorcore.frameId;
43397 if(!this.disable.font && !Roo.isSafari){
43399 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43400 if(name != this.fontSelect.dom.value){
43401 this.fontSelect.dom.value = name;
43405 if(!this.disable.format){
43406 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43407 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43408 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43410 if(!this.disable.alignments){
43411 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43412 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43413 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43415 if(!Roo.isSafari && !this.disable.lists){
43416 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43417 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43420 var ans = this.editorcore.getAllAncestors();
43421 if (this.formatCombo) {
43424 var store = this.formatCombo.store;
43425 this.formatCombo.setValue("");
43426 for (var i =0; i < ans.length;i++) {
43427 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43429 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43437 // hides menus... - so this cant be on a menu...
43438 Roo.menu.MenuMgr.hideAll();
43440 //this.editorsyncValue();
43444 createFontOptions : function(){
43445 var buf = [], fs = this.fontFamilies, ff, lc;
43449 for(var i = 0, len = fs.length; i< len; i++){
43451 lc = ff.toLowerCase();
43453 '<option value="',lc,'" style="font-family:',ff,';"',
43454 (this.defaultFont == lc ? ' selected="true">' : '>'),
43459 return buf.join('');
43462 toggleSourceEdit : function(sourceEditMode){
43464 Roo.log("toolbar toogle");
43465 if(sourceEditMode === undefined){
43466 sourceEditMode = !this.sourceEditMode;
43468 this.sourceEditMode = sourceEditMode === true;
43469 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43470 // just toggle the button?
43471 if(btn.pressed !== this.sourceEditMode){
43472 btn.toggle(this.sourceEditMode);
43476 if(sourceEditMode){
43477 Roo.log("disabling buttons");
43478 this.tb.items.each(function(item){
43479 if(item.cmd != 'sourceedit'){
43485 Roo.log("enabling buttons");
43486 if(this.editorcore.initialized){
43487 this.tb.items.each(function(item){
43493 Roo.log("calling toggole on editor");
43494 // tell the editor that it's been pressed..
43495 this.editor.toggleSourceEdit(sourceEditMode);
43499 * Object collection of toolbar tooltips for the buttons in the editor. The key
43500 * is the command id associated with that button and the value is a valid QuickTips object.
43505 title: 'Bold (Ctrl+B)',
43506 text: 'Make the selected text bold.',
43507 cls: 'x-html-editor-tip'
43510 title: 'Italic (Ctrl+I)',
43511 text: 'Make the selected text italic.',
43512 cls: 'x-html-editor-tip'
43520 title: 'Bold (Ctrl+B)',
43521 text: 'Make the selected text bold.',
43522 cls: 'x-html-editor-tip'
43525 title: 'Italic (Ctrl+I)',
43526 text: 'Make the selected text italic.',
43527 cls: 'x-html-editor-tip'
43530 title: 'Underline (Ctrl+U)',
43531 text: 'Underline the selected text.',
43532 cls: 'x-html-editor-tip'
43534 increasefontsize : {
43535 title: 'Grow Text',
43536 text: 'Increase the font size.',
43537 cls: 'x-html-editor-tip'
43539 decreasefontsize : {
43540 title: 'Shrink Text',
43541 text: 'Decrease the font size.',
43542 cls: 'x-html-editor-tip'
43545 title: 'Text Highlight Color',
43546 text: 'Change the background color of the selected text.',
43547 cls: 'x-html-editor-tip'
43550 title: 'Font Color',
43551 text: 'Change the color of the selected text.',
43552 cls: 'x-html-editor-tip'
43555 title: 'Align Text Left',
43556 text: 'Align text to the left.',
43557 cls: 'x-html-editor-tip'
43560 title: 'Center Text',
43561 text: 'Center text in the editor.',
43562 cls: 'x-html-editor-tip'
43565 title: 'Align Text Right',
43566 text: 'Align text to the right.',
43567 cls: 'x-html-editor-tip'
43569 insertunorderedlist : {
43570 title: 'Bullet List',
43571 text: 'Start a bulleted list.',
43572 cls: 'x-html-editor-tip'
43574 insertorderedlist : {
43575 title: 'Numbered List',
43576 text: 'Start a numbered list.',
43577 cls: 'x-html-editor-tip'
43580 title: 'Hyperlink',
43581 text: 'Make the selected text a hyperlink.',
43582 cls: 'x-html-editor-tip'
43585 title: 'Source Edit',
43586 text: 'Switch to source editing mode.',
43587 cls: 'x-html-editor-tip'
43591 onDestroy : function(){
43594 this.tb.items.each(function(item){
43596 item.menu.removeAll();
43598 item.menu.el.destroy();
43606 onFirstFocus: function() {
43607 this.tb.items.each(function(item){
43616 // <script type="text/javascript">
43619 * Ext JS Library 1.1.1
43620 * Copyright(c) 2006-2007, Ext JS, LLC.
43627 * @class Roo.form.HtmlEditor.ToolbarContext
43632 new Roo.form.HtmlEditor({
43635 { xtype: 'ToolbarStandard', styles : {} }
43636 { xtype: 'ToolbarContext', disable : {} }
43642 * @config : {Object} disable List of elements to disable.. (not done yet.)
43643 * @config : {Object} styles Map of styles available.
43647 Roo.form.HtmlEditor.ToolbarContext = function(config)
43650 Roo.apply(this, config);
43651 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43652 // dont call parent... till later.
43653 this.styles = this.styles || {};
43658 Roo.form.HtmlEditor.ToolbarContext.types = {
43670 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
43736 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
43741 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
43751 style : 'fontFamily',
43752 displayField: 'display',
43753 optname : 'font-family',
43802 // should we really allow this??
43803 // should this just be
43814 style : 'fontFamily',
43815 displayField: 'display',
43816 optname : 'font-family',
43823 style : 'fontFamily',
43824 displayField: 'display',
43825 optname : 'font-family',
43832 style : 'fontFamily',
43833 displayField: 'display',
43834 optname : 'font-family',
43845 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
43846 Roo.form.HtmlEditor.ToolbarContext.stores = false;
43848 Roo.form.HtmlEditor.ToolbarContext.options = {
43850 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
43851 [ 'Courier New', 'Courier New'],
43852 [ 'Tahoma', 'Tahoma'],
43853 [ 'Times New Roman,serif', 'Times'],
43854 [ 'Verdana','Verdana' ]
43858 // fixme - these need to be configurable..
43861 Roo.form.HtmlEditor.ToolbarContext.types
43864 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
43871 editorcore : false,
43873 * @cfg {Object} disable List of toolbar elements to disable
43878 * @cfg {Object} styles List of styles
43879 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
43881 * These must be defined in the page, so they get rendered correctly..
43892 init : function(editor)
43894 this.editor = editor;
43895 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43896 var editorcore = this.editorcore;
43898 var fid = editorcore.frameId;
43900 function btn(id, toggle, handler){
43901 var xid = fid + '-'+ id ;
43905 cls : 'x-btn-icon x-edit-'+id,
43906 enableToggle:toggle !== false,
43907 scope: editorcore, // was editor...
43908 handler:handler||editorcore.relayBtnCmd,
43909 clickEvent:'mousedown',
43910 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43914 // create a new element.
43915 var wdiv = editor.wrap.createChild({
43917 }, editor.wrap.dom.firstChild.nextSibling, true);
43919 // can we do this more than once??
43921 // stop form submits
43924 // disable everything...
43925 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43926 this.toolbars = {};
43928 for (var i in ty) {
43930 this.toolbars[i] = this.buildToolbar(ty[i],i);
43932 this.tb = this.toolbars.BODY;
43934 this.buildFooter();
43935 this.footer.show();
43936 editor.on('hide', function( ) { this.footer.hide() }, this);
43937 editor.on('show', function( ) { this.footer.show() }, this);
43940 this.rendered = true;
43942 // the all the btns;
43943 editor.on('editorevent', this.updateToolbar, this);
43944 // other toolbars need to implement this..
43945 //editor.on('editmodechange', this.updateToolbar, this);
43951 * Protected method that will not generally be called directly. It triggers
43952 * a toolbar update by reading the markup state of the current selection in the editor.
43954 updateToolbar: function(editor,ev,sel){
43957 // capture mouse up - this is handy for selecting images..
43958 // perhaps should go somewhere else...
43959 if(!this.editorcore.activated){
43960 this.editor.onFirstFocus();
43964 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
43965 // selectNode - might want to handle IE?
43967 (ev.type == 'mouseup' || ev.type == 'click' ) &&
43968 ev.target && ev.target.tagName == 'IMG') {
43969 // they have click on an image...
43970 // let's see if we can change the selection...
43973 var nodeRange = sel.ownerDocument.createRange();
43975 nodeRange.selectNode(sel);
43977 nodeRange.selectNodeContents(sel);
43979 //nodeRange.collapse(true);
43980 var s = this.editorcore.win.getSelection();
43981 s.removeAllRanges();
43982 s.addRange(nodeRange);
43986 var updateFooter = sel ? false : true;
43989 var ans = this.editorcore.getAllAncestors();
43992 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43995 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
43996 sel = sel ? sel : this.editorcore.doc.body;
43997 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44000 // pick a menu that exists..
44001 var tn = sel.tagName.toUpperCase();
44002 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44004 tn = sel.tagName.toUpperCase();
44006 var lastSel = this.tb.selectedNode
44008 this.tb.selectedNode = sel;
44010 // if current menu does not match..
44011 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
44014 ///console.log("show: " + tn);
44015 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44018 this.tb.items.first().el.innerHTML = tn + ': ';
44021 // update attributes
44022 if (this.tb.fields) {
44023 this.tb.fields.each(function(e) {
44025 e.setValue(sel.style[e.stylename]);
44028 e.setValue(sel.getAttribute(e.attrname));
44032 var hasStyles = false;
44033 for(var i in this.styles) {
44040 var st = this.tb.fields.item(0);
44042 st.store.removeAll();
44045 var cn = sel.className.split(/\s+/);
44048 if (this.styles['*']) {
44050 Roo.each(this.styles['*'], function(v) {
44051 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44054 if (this.styles[tn]) {
44055 Roo.each(this.styles[tn], function(v) {
44056 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44060 st.store.loadData(avs);
44064 // flag our selected Node.
44065 this.tb.selectedNode = sel;
44068 Roo.menu.MenuMgr.hideAll();
44072 if (!updateFooter) {
44073 //this.footDisp.dom.innerHTML = '';
44076 // update the footer
44080 this.footerEls = ans.reverse();
44081 Roo.each(this.footerEls, function(a,i) {
44082 if (!a) { return; }
44083 html += html.length ? ' > ' : '';
44085 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44090 var sz = this.footDisp.up('td').getSize();
44091 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44092 this.footDisp.dom.style.marginLeft = '5px';
44094 this.footDisp.dom.style.overflow = 'hidden';
44096 this.footDisp.dom.innerHTML = html;
44098 //this.editorsyncValue();
44105 onDestroy : function(){
44108 this.tb.items.each(function(item){
44110 item.menu.removeAll();
44112 item.menu.el.destroy();
44120 onFirstFocus: function() {
44121 // need to do this for all the toolbars..
44122 this.tb.items.each(function(item){
44126 buildToolbar: function(tlist, nm)
44128 var editor = this.editor;
44129 var editorcore = this.editorcore;
44130 // create a new element.
44131 var wdiv = editor.wrap.createChild({
44133 }, editor.wrap.dom.firstChild.nextSibling, true);
44136 var tb = new Roo.Toolbar(wdiv);
44139 tb.add(nm+ ": ");
44142 for(var i in this.styles) {
44147 if (styles && styles.length) {
44149 // this needs a multi-select checkbox...
44150 tb.addField( new Roo.form.ComboBox({
44151 store: new Roo.data.SimpleStore({
44153 fields: ['val', 'selected'],
44156 name : '-roo-edit-className',
44157 attrname : 'className',
44158 displayField: 'val',
44162 triggerAction: 'all',
44163 emptyText:'Select Style',
44164 selectOnFocus:true,
44167 'select': function(c, r, i) {
44168 // initial support only for on class per el..
44169 tb.selectedNode.className = r ? r.get('val') : '';
44170 editorcore.syncValue();
44177 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44178 var tbops = tbc.options;
44180 for (var i in tlist) {
44182 var item = tlist[i];
44183 tb.add(item.title + ": ");
44186 //optname == used so you can configure the options available..
44187 var opts = item.opts ? item.opts : false;
44188 if (item.optname) {
44189 opts = tbops[item.optname];
44194 // opts == pulldown..
44195 tb.addField( new Roo.form.ComboBox({
44196 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44198 fields: ['val', 'display'],
44201 name : '-roo-edit-' + i,
44203 stylename : item.style ? item.style : false,
44204 displayField: item.displayField ? item.displayField : 'val',
44205 valueField : 'val',
44207 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44209 triggerAction: 'all',
44210 emptyText:'Select',
44211 selectOnFocus:true,
44212 width: item.width ? item.width : 130,
44214 'select': function(c, r, i) {
44216 tb.selectedNode.style[c.stylename] = r.get('val');
44219 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44228 tb.addField( new Roo.form.TextField({
44231 //allowBlank:false,
44236 tb.addField( new Roo.form.TextField({
44237 name: '-roo-edit-' + i,
44244 'change' : function(f, nv, ov) {
44245 tb.selectedNode.setAttribute(f.attrname, nv);
44254 text: 'Remove Tag',
44257 click : function ()
44260 // undo does not work.
44262 var sn = tb.selectedNode;
44264 var pn = sn.parentNode;
44266 var stn = sn.childNodes[0];
44267 var en = sn.childNodes[sn.childNodes.length - 1 ];
44268 while (sn.childNodes.length) {
44269 var node = sn.childNodes[0];
44270 sn.removeChild(node);
44272 pn.insertBefore(node, sn);
44275 pn.removeChild(sn);
44276 var range = editorcore.createRange();
44278 range.setStart(stn,0);
44279 range.setEnd(en,0); //????
44280 //range.selectNode(sel);
44283 var selection = editorcore.getSelection();
44284 selection.removeAllRanges();
44285 selection.addRange(range);
44289 //_this.updateToolbar(null, null, pn);
44290 _this.updateToolbar(null, null, null);
44291 _this.footDisp.dom.innerHTML = '';
44301 tb.el.on('click', function(e){
44302 e.preventDefault(); // what does this do?
44304 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44307 // dont need to disable them... as they will get hidden
44312 buildFooter : function()
44315 var fel = this.editor.wrap.createChild();
44316 this.footer = new Roo.Toolbar(fel);
44317 // toolbar has scrolly on left / right?
44318 var footDisp= new Roo.Toolbar.Fill();
44324 handler : function() {
44325 _t.footDisp.scrollTo('left',0,true)
44329 this.footer.add( footDisp );
44334 handler : function() {
44336 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44340 var fel = Roo.get(footDisp.el);
44341 fel.addClass('x-editor-context');
44342 this.footDispWrap = fel;
44343 this.footDispWrap.overflow = 'hidden';
44345 this.footDisp = fel.createChild();
44346 this.footDispWrap.on('click', this.onContextClick, this)
44350 onContextClick : function (ev,dom)
44352 ev.preventDefault();
44353 var cn = dom.className;
44355 if (!cn.match(/x-ed-loc-/)) {
44358 var n = cn.split('-').pop();
44359 var ans = this.footerEls;
44363 var range = this.editorcore.createRange();
44365 range.selectNodeContents(sel);
44366 //range.selectNode(sel);
44369 var selection = this.editorcore.getSelection();
44370 selection.removeAllRanges();
44371 selection.addRange(range);
44375 this.updateToolbar(null, null, sel);
44392 * Ext JS Library 1.1.1
44393 * Copyright(c) 2006-2007, Ext JS, LLC.
44395 * Originally Released Under LGPL - original licence link has changed is not relivant.
44398 * <script type="text/javascript">
44402 * @class Roo.form.BasicForm
44403 * @extends Roo.util.Observable
44404 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44406 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44407 * @param {Object} config Configuration options
44409 Roo.form.BasicForm = function(el, config){
44410 this.allItems = [];
44411 this.childForms = [];
44412 Roo.apply(this, config);
44414 * The Roo.form.Field items in this form.
44415 * @type MixedCollection
44419 this.items = new Roo.util.MixedCollection(false, function(o){
44420 return o.id || (o.id = Roo.id());
44424 * @event beforeaction
44425 * Fires before any action is performed. Return false to cancel the action.
44426 * @param {Form} this
44427 * @param {Action} action The action to be performed
44429 beforeaction: true,
44431 * @event actionfailed
44432 * Fires when an action fails.
44433 * @param {Form} this
44434 * @param {Action} action The action that failed
44436 actionfailed : true,
44438 * @event actioncomplete
44439 * Fires when an action is completed.
44440 * @param {Form} this
44441 * @param {Action} action The action that completed
44443 actioncomplete : true
44448 Roo.form.BasicForm.superclass.constructor.call(this);
44451 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44453 * @cfg {String} method
44454 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
44457 * @cfg {DataReader} reader
44458 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
44459 * This is optional as there is built-in support for processing JSON.
44462 * @cfg {DataReader} errorReader
44463 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
44464 * This is completely optional as there is built-in support for processing JSON.
44467 * @cfg {String} url
44468 * The URL to use for form actions if one isn't supplied in the action options.
44471 * @cfg {Boolean} fileUpload
44472 * Set to true if this form is a file upload.
44476 * @cfg {Object} baseParams
44477 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
44482 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
44487 activeAction : null,
44490 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
44491 * or setValues() data instead of when the form was first created.
44493 trackResetOnLoad : false,
44497 * childForms - used for multi-tab forms
44500 childForms : false,
44503 * allItems - full list of fields.
44509 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
44510 * element by passing it or its id or mask the form itself by passing in true.
44513 waitMsgTarget : false,
44516 initEl : function(el){
44517 this.el = Roo.get(el);
44518 this.id = this.el.id || Roo.id();
44519 this.el.on('submit', this.onSubmit, this);
44520 this.el.addClass('x-form');
44524 onSubmit : function(e){
44529 * Returns true if client-side validation on the form is successful.
44532 isValid : function(){
44534 this.items.each(function(f){
44543 * Returns true if any fields in this form have changed since their original load.
44546 isDirty : function(){
44548 this.items.each(function(f){
44558 * Performs a predefined action (submit or load) or custom actions you define on this form.
44559 * @param {String} actionName The name of the action type
44560 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
44561 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
44562 * accept other config options):
44564 Property Type Description
44565 ---------------- --------------- ----------------------------------------------------------------------------------
44566 url String The url for the action (defaults to the form's url)
44567 method String The form method to use (defaults to the form's method, or POST if not defined)
44568 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
44569 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
44570 validate the form on the client (defaults to false)
44572 * @return {BasicForm} this
44574 doAction : function(action, options){
44575 if(typeof action == 'string'){
44576 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
44578 if(this.fireEvent('beforeaction', this, action) !== false){
44579 this.beforeAction(action);
44580 action.run.defer(100, action);
44586 * Shortcut to do a submit action.
44587 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44588 * @return {BasicForm} this
44590 submit : function(options){
44591 this.doAction('submit', options);
44596 * Shortcut to do a load action.
44597 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44598 * @return {BasicForm} this
44600 load : function(options){
44601 this.doAction('load', options);
44606 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
44607 * @param {Record} record The record to edit
44608 * @return {BasicForm} this
44610 updateRecord : function(record){
44611 record.beginEdit();
44612 var fs = record.fields;
44613 fs.each(function(f){
44614 var field = this.findField(f.name);
44616 record.set(f.name, field.getValue());
44624 * Loads an Roo.data.Record into this form.
44625 * @param {Record} record The record to load
44626 * @return {BasicForm} this
44628 loadRecord : function(record){
44629 this.setValues(record.data);
44634 beforeAction : function(action){
44635 var o = action.options;
44638 if(this.waitMsgTarget === true){
44639 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
44640 }else if(this.waitMsgTarget){
44641 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
44642 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
44644 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
44650 afterAction : function(action, success){
44651 this.activeAction = null;
44652 var o = action.options;
44654 if(this.waitMsgTarget === true){
44656 }else if(this.waitMsgTarget){
44657 this.waitMsgTarget.unmask();
44659 Roo.MessageBox.updateProgress(1);
44660 Roo.MessageBox.hide();
44667 Roo.callback(o.success, o.scope, [this, action]);
44668 this.fireEvent('actioncomplete', this, action);
44672 // failure condition..
44673 // we have a scenario where updates need confirming.
44674 // eg. if a locking scenario exists..
44675 // we look for { errors : { needs_confirm : true }} in the response.
44677 (typeof(action.result) != 'undefined') &&
44678 (typeof(action.result.errors) != 'undefined') &&
44679 (typeof(action.result.errors.needs_confirm) != 'undefined')
44682 Roo.MessageBox.confirm(
44683 "Change requires confirmation",
44684 action.result.errorMsg,
44689 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
44699 Roo.callback(o.failure, o.scope, [this, action]);
44700 // show an error message if no failed handler is set..
44701 if (!this.hasListener('actionfailed')) {
44702 Roo.MessageBox.alert("Error",
44703 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
44704 action.result.errorMsg :
44705 "Saving Failed, please check your entries or try again"
44709 this.fireEvent('actionfailed', this, action);
44715 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
44716 * @param {String} id The value to search for
44719 findField : function(id){
44720 var field = this.items.get(id);
44722 this.items.each(function(f){
44723 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
44729 return field || null;
44733 * Add a secondary form to this one,
44734 * Used to provide tabbed forms. One form is primary, with hidden values
44735 * which mirror the elements from the other forms.
44737 * @param {Roo.form.Form} form to add.
44740 addForm : function(form)
44743 if (this.childForms.indexOf(form) > -1) {
44747 this.childForms.push(form);
44749 Roo.each(form.allItems, function (fe) {
44751 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
44752 if (this.findField(n)) { // already added..
44755 var add = new Roo.form.Hidden({
44758 add.render(this.el);
44765 * Mark fields in this form invalid in bulk.
44766 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
44767 * @return {BasicForm} this
44769 markInvalid : function(errors){
44770 if(errors instanceof Array){
44771 for(var i = 0, len = errors.length; i < len; i++){
44772 var fieldError = errors[i];
44773 var f = this.findField(fieldError.id);
44775 f.markInvalid(fieldError.msg);
44781 if(typeof errors[id] != 'function' && (field = this.findField(id))){
44782 field.markInvalid(errors[id]);
44786 Roo.each(this.childForms || [], function (f) {
44787 f.markInvalid(errors);
44794 * Set values for fields in this form in bulk.
44795 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
44796 * @return {BasicForm} this
44798 setValues : function(values){
44799 if(values instanceof Array){ // array of objects
44800 for(var i = 0, len = values.length; i < len; i++){
44802 var f = this.findField(v.id);
44804 f.setValue(v.value);
44805 if(this.trackResetOnLoad){
44806 f.originalValue = f.getValue();
44810 }else{ // object hash
44813 if(typeof values[id] != 'function' && (field = this.findField(id))){
44815 if (field.setFromData &&
44816 field.valueField &&
44817 field.displayField &&
44818 // combos' with local stores can
44819 // be queried via setValue()
44820 // to set their value..
44821 (field.store && !field.store.isLocal)
44825 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44826 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44827 field.setFromData(sd);
44830 field.setValue(values[id]);
44834 if(this.trackResetOnLoad){
44835 field.originalValue = field.getValue();
44841 Roo.each(this.childForms || [], function (f) {
44842 f.setValues(values);
44849 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
44850 * they are returned as an array.
44851 * @param {Boolean} asString
44854 getValues : function(asString){
44855 if (this.childForms) {
44856 // copy values from the child forms
44857 Roo.each(this.childForms, function (f) {
44858 this.setValues(f.getValues());
44864 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
44865 if(asString === true){
44868 return Roo.urlDecode(fs);
44872 * Returns the fields in this form as an object with key/value pairs.
44873 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
44876 getFieldValues : function(with_hidden)
44878 if (this.childForms) {
44879 // copy values from the child forms
44880 // should this call getFieldValues - probably not as we do not currently copy
44881 // hidden fields when we generate..
44882 Roo.each(this.childForms, function (f) {
44883 this.setValues(f.getValues());
44888 this.items.each(function(f){
44889 if (!f.getName()) {
44892 var v = f.getValue();
44893 if (f.inputType =='radio') {
44894 if (typeof(ret[f.getName()]) == 'undefined') {
44895 ret[f.getName()] = ''; // empty..
44898 if (!f.el.dom.checked) {
44902 v = f.el.dom.value;
44906 // not sure if this supported any more..
44907 if ((typeof(v) == 'object') && f.getRawValue) {
44908 v = f.getRawValue() ; // dates..
44910 // combo boxes where name != hiddenName...
44911 if (f.name != f.getName()) {
44912 ret[f.name] = f.getRawValue();
44914 ret[f.getName()] = v;
44921 * Clears all invalid messages in this form.
44922 * @return {BasicForm} this
44924 clearInvalid : function(){
44925 this.items.each(function(f){
44929 Roo.each(this.childForms || [], function (f) {
44938 * Resets this form.
44939 * @return {BasicForm} this
44941 reset : function(){
44942 this.items.each(function(f){
44946 Roo.each(this.childForms || [], function (f) {
44955 * Add Roo.form components to this form.
44956 * @param {Field} field1
44957 * @param {Field} field2 (optional)
44958 * @param {Field} etc (optional)
44959 * @return {BasicForm} this
44962 this.items.addAll(Array.prototype.slice.call(arguments, 0));
44968 * Removes a field from the items collection (does NOT remove its markup).
44969 * @param {Field} field
44970 * @return {BasicForm} this
44972 remove : function(field){
44973 this.items.remove(field);
44978 * Looks at the fields in this form, checks them for an id attribute,
44979 * and calls applyTo on the existing dom element with that id.
44980 * @return {BasicForm} this
44982 render : function(){
44983 this.items.each(function(f){
44984 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
44992 * Calls {@link Ext#apply} for all fields in this form with the passed object.
44993 * @param {Object} values
44994 * @return {BasicForm} this
44996 applyToFields : function(o){
44997 this.items.each(function(f){
45004 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45005 * @param {Object} values
45006 * @return {BasicForm} this
45008 applyIfToFields : function(o){
45009 this.items.each(function(f){
45017 Roo.BasicForm = Roo.form.BasicForm;/*
45019 * Ext JS Library 1.1.1
45020 * Copyright(c) 2006-2007, Ext JS, LLC.
45022 * Originally Released Under LGPL - original licence link has changed is not relivant.
45025 * <script type="text/javascript">
45029 * @class Roo.form.Form
45030 * @extends Roo.form.BasicForm
45031 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45033 * @param {Object} config Configuration options
45035 Roo.form.Form = function(config){
45037 if (config.items) {
45038 xitems = config.items;
45039 delete config.items;
45043 Roo.form.Form.superclass.constructor.call(this, null, config);
45044 this.url = this.url || this.action;
45046 this.root = new Roo.form.Layout(Roo.applyIf({
45050 this.active = this.root;
45052 * Array of all the buttons that have been added to this form via {@link addButton}
45056 this.allItems = [];
45059 * @event clientvalidation
45060 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45061 * @param {Form} this
45062 * @param {Boolean} valid true if the form has passed client-side validation
45064 clientvalidation: true,
45067 * Fires when the form is rendered
45068 * @param {Roo.form.Form} form
45073 if (this.progressUrl) {
45074 // push a hidden field onto the list of fields..
45078 name : 'UPLOAD_IDENTIFIER'
45083 Roo.each(xitems, this.addxtype, this);
45089 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45091 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45094 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45097 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45099 buttonAlign:'center',
45102 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45107 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45108 * This property cascades to child containers if not set.
45113 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45114 * fires a looping event with that state. This is required to bind buttons to the valid
45115 * state using the config value formBind:true on the button.
45117 monitorValid : false,
45120 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45125 * @cfg {String} progressUrl - Url to return progress data
45128 progressUrl : false,
45131 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45132 * fields are added and the column is closed. If no fields are passed the column remains open
45133 * until end() is called.
45134 * @param {Object} config The config to pass to the column
45135 * @param {Field} field1 (optional)
45136 * @param {Field} field2 (optional)
45137 * @param {Field} etc (optional)
45138 * @return Column The column container object
45140 column : function(c){
45141 var col = new Roo.form.Column(c);
45143 if(arguments.length > 1){ // duplicate code required because of Opera
45144 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45151 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45152 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45153 * until end() is called.
45154 * @param {Object} config The config to pass to the fieldset
45155 * @param {Field} field1 (optional)
45156 * @param {Field} field2 (optional)
45157 * @param {Field} etc (optional)
45158 * @return FieldSet The fieldset container object
45160 fieldset : function(c){
45161 var fs = new Roo.form.FieldSet(c);
45163 if(arguments.length > 1){ // duplicate code required because of Opera
45164 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45171 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45172 * fields are added and the container is closed. If no fields are passed the container remains open
45173 * until end() is called.
45174 * @param {Object} config The config to pass to the Layout
45175 * @param {Field} field1 (optional)
45176 * @param {Field} field2 (optional)
45177 * @param {Field} etc (optional)
45178 * @return Layout The container object
45180 container : function(c){
45181 var l = new Roo.form.Layout(c);
45183 if(arguments.length > 1){ // duplicate code required because of Opera
45184 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45191 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45192 * @param {Object} container A Roo.form.Layout or subclass of Layout
45193 * @return {Form} this
45195 start : function(c){
45196 // cascade label info
45197 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45198 this.active.stack.push(c);
45199 c.ownerCt = this.active;
45205 * Closes the current open container
45206 * @return {Form} this
45209 if(this.active == this.root){
45212 this.active = this.active.ownerCt;
45217 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45218 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45219 * as the label of the field.
45220 * @param {Field} field1
45221 * @param {Field} field2 (optional)
45222 * @param {Field} etc. (optional)
45223 * @return {Form} this
45226 this.active.stack.push.apply(this.active.stack, arguments);
45227 this.allItems.push.apply(this.allItems,arguments);
45229 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45230 if(a[i].isFormField){
45235 Roo.form.Form.superclass.add.apply(this, r);
45245 * Find any element that has been added to a form, using it's ID or name
45246 * This can include framesets, columns etc. along with regular fields..
45247 * @param {String} id - id or name to find.
45249 * @return {Element} e - or false if nothing found.
45251 findbyId : function(id)
45257 Roo.each(this.allItems, function(f){
45258 if (f.id == id || f.name == id ){
45269 * Render this form into the passed container. This should only be called once!
45270 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45271 * @return {Form} this
45273 render : function(ct)
45279 var o = this.autoCreate || {
45281 method : this.method || 'POST',
45282 id : this.id || Roo.id()
45284 this.initEl(ct.createChild(o));
45286 this.root.render(this.el);
45290 this.items.each(function(f){
45291 f.render('x-form-el-'+f.id);
45294 if(this.buttons.length > 0){
45295 // tables are required to maintain order and for correct IE layout
45296 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45297 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45298 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45300 var tr = tb.getElementsByTagName('tr')[0];
45301 for(var i = 0, len = this.buttons.length; i < len; i++) {
45302 var b = this.buttons[i];
45303 var td = document.createElement('td');
45304 td.className = 'x-form-btn-td';
45305 b.render(tr.appendChild(td));
45308 if(this.monitorValid){ // initialize after render
45309 this.startMonitoring();
45311 this.fireEvent('rendered', this);
45316 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45317 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45318 * object or a valid Roo.DomHelper element config
45319 * @param {Function} handler The function called when the button is clicked
45320 * @param {Object} scope (optional) The scope of the handler function
45321 * @return {Roo.Button}
45323 addButton : function(config, handler, scope){
45327 minWidth: this.minButtonWidth,
45330 if(typeof config == "string"){
45333 Roo.apply(bc, config);
45335 var btn = new Roo.Button(null, bc);
45336 this.buttons.push(btn);
45341 * Adds a series of form elements (using the xtype property as the factory method.
45342 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45343 * @param {Object} config
45346 addxtype : function()
45348 var ar = Array.prototype.slice.call(arguments, 0);
45350 for(var i = 0; i < ar.length; i++) {
45352 continue; // skip -- if this happends something invalid got sent, we
45353 // should ignore it, as basically that interface element will not show up
45354 // and that should be pretty obvious!!
45357 if (Roo.form[ar[i].xtype]) {
45359 var fe = Roo.factory(ar[i], Roo.form);
45365 fe.store.form = this;
45370 this.allItems.push(fe);
45371 if (fe.items && fe.addxtype) {
45372 fe.addxtype.apply(fe, fe.items);
45382 // console.log('adding ' + ar[i].xtype);
45384 if (ar[i].xtype == 'Button') {
45385 //console.log('adding button');
45386 //console.log(ar[i]);
45387 this.addButton(ar[i]);
45388 this.allItems.push(fe);
45392 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45393 alert('end is not supported on xtype any more, use items');
45395 // //console.log('adding end');
45403 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45404 * option "monitorValid"
45406 startMonitoring : function(){
45409 Roo.TaskMgr.start({
45410 run : this.bindHandler,
45411 interval : this.monitorPoll || 200,
45418 * Stops monitoring of the valid state of this form
45420 stopMonitoring : function(){
45421 this.bound = false;
45425 bindHandler : function(){
45427 return false; // stops binding
45430 this.items.each(function(f){
45431 if(!f.isValid(true)){
45436 for(var i = 0, len = this.buttons.length; i < len; i++){
45437 var btn = this.buttons[i];
45438 if(btn.formBind === true && btn.disabled === valid){
45439 btn.setDisabled(!valid);
45442 this.fireEvent('clientvalidation', this, valid);
45456 Roo.Form = Roo.form.Form;
45459 * Ext JS Library 1.1.1
45460 * Copyright(c) 2006-2007, Ext JS, LLC.
45462 * Originally Released Under LGPL - original licence link has changed is not relivant.
45465 * <script type="text/javascript">
45468 // as we use this in bootstrap.
45469 Roo.namespace('Roo.form');
45471 * @class Roo.form.Action
45472 * Internal Class used to handle form actions
45474 * @param {Roo.form.BasicForm} el The form element or its id
45475 * @param {Object} config Configuration options
45480 // define the action interface
45481 Roo.form.Action = function(form, options){
45483 this.options = options || {};
45486 * Client Validation Failed
45489 Roo.form.Action.CLIENT_INVALID = 'client';
45491 * Server Validation Failed
45494 Roo.form.Action.SERVER_INVALID = 'server';
45496 * Connect to Server Failed
45499 Roo.form.Action.CONNECT_FAILURE = 'connect';
45501 * Reading Data from Server Failed
45504 Roo.form.Action.LOAD_FAILURE = 'load';
45506 Roo.form.Action.prototype = {
45508 failureType : undefined,
45509 response : undefined,
45510 result : undefined,
45512 // interface method
45513 run : function(options){
45517 // interface method
45518 success : function(response){
45522 // interface method
45523 handleResponse : function(response){
45527 // default connection failure
45528 failure : function(response){
45530 this.response = response;
45531 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45532 this.form.afterAction(this, false);
45535 processResponse : function(response){
45536 this.response = response;
45537 if(!response.responseText){
45540 this.result = this.handleResponse(response);
45541 return this.result;
45544 // utility functions used internally
45545 getUrl : function(appendParams){
45546 var url = this.options.url || this.form.url || this.form.el.dom.action;
45548 var p = this.getParams();
45550 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
45556 getMethod : function(){
45557 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
45560 getParams : function(){
45561 var bp = this.form.baseParams;
45562 var p = this.options.params;
45564 if(typeof p == "object"){
45565 p = Roo.urlEncode(Roo.applyIf(p, bp));
45566 }else if(typeof p == 'string' && bp){
45567 p += '&' + Roo.urlEncode(bp);
45570 p = Roo.urlEncode(bp);
45575 createCallback : function(){
45577 success: this.success,
45578 failure: this.failure,
45580 timeout: (this.form.timeout*1000),
45581 upload: this.form.fileUpload ? this.success : undefined
45586 Roo.form.Action.Submit = function(form, options){
45587 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
45590 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
45593 haveProgress : false,
45594 uploadComplete : false,
45596 // uploadProgress indicator.
45597 uploadProgress : function()
45599 if (!this.form.progressUrl) {
45603 if (!this.haveProgress) {
45604 Roo.MessageBox.progress("Uploading", "Uploading");
45606 if (this.uploadComplete) {
45607 Roo.MessageBox.hide();
45611 this.haveProgress = true;
45613 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
45615 var c = new Roo.data.Connection();
45617 url : this.form.progressUrl,
45622 success : function(req){
45623 //console.log(data);
45627 rdata = Roo.decode(req.responseText)
45629 Roo.log("Invalid data from server..");
45633 if (!rdata || !rdata.success) {
45635 Roo.MessageBox.alert(Roo.encode(rdata));
45638 var data = rdata.data;
45640 if (this.uploadComplete) {
45641 Roo.MessageBox.hide();
45646 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
45647 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
45650 this.uploadProgress.defer(2000,this);
45653 failure: function(data) {
45654 Roo.log('progress url failed ');
45665 // run get Values on the form, so it syncs any secondary forms.
45666 this.form.getValues();
45668 var o = this.options;
45669 var method = this.getMethod();
45670 var isPost = method == 'POST';
45671 if(o.clientValidation === false || this.form.isValid()){
45673 if (this.form.progressUrl) {
45674 this.form.findField('UPLOAD_IDENTIFIER').setValue(
45675 (new Date() * 1) + '' + Math.random());
45680 Roo.Ajax.request(Roo.apply(this.createCallback(), {
45681 form:this.form.el.dom,
45682 url:this.getUrl(!isPost),
45684 params:isPost ? this.getParams() : null,
45685 isUpload: this.form.fileUpload
45688 this.uploadProgress();
45690 }else if (o.clientValidation !== false){ // client validation failed
45691 this.failureType = Roo.form.Action.CLIENT_INVALID;
45692 this.form.afterAction(this, false);
45696 success : function(response)
45698 this.uploadComplete= true;
45699 if (this.haveProgress) {
45700 Roo.MessageBox.hide();
45704 var result = this.processResponse(response);
45705 if(result === true || result.success){
45706 this.form.afterAction(this, true);
45710 this.form.markInvalid(result.errors);
45711 this.failureType = Roo.form.Action.SERVER_INVALID;
45713 this.form.afterAction(this, false);
45715 failure : function(response)
45717 this.uploadComplete= true;
45718 if (this.haveProgress) {
45719 Roo.MessageBox.hide();
45722 this.response = response;
45723 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45724 this.form.afterAction(this, false);
45727 handleResponse : function(response){
45728 if(this.form.errorReader){
45729 var rs = this.form.errorReader.read(response);
45732 for(var i = 0, len = rs.records.length; i < len; i++) {
45733 var r = rs.records[i];
45734 errors[i] = r.data;
45737 if(errors.length < 1){
45741 success : rs.success,
45747 ret = Roo.decode(response.responseText);
45751 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
45761 Roo.form.Action.Load = function(form, options){
45762 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
45763 this.reader = this.form.reader;
45766 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
45771 Roo.Ajax.request(Roo.apply(
45772 this.createCallback(), {
45773 method:this.getMethod(),
45774 url:this.getUrl(false),
45775 params:this.getParams()
45779 success : function(response){
45781 var result = this.processResponse(response);
45782 if(result === true || !result.success || !result.data){
45783 this.failureType = Roo.form.Action.LOAD_FAILURE;
45784 this.form.afterAction(this, false);
45787 this.form.clearInvalid();
45788 this.form.setValues(result.data);
45789 this.form.afterAction(this, true);
45792 handleResponse : function(response){
45793 if(this.form.reader){
45794 var rs = this.form.reader.read(response);
45795 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
45797 success : rs.success,
45801 return Roo.decode(response.responseText);
45805 Roo.form.Action.ACTION_TYPES = {
45806 'load' : Roo.form.Action.Load,
45807 'submit' : Roo.form.Action.Submit
45810 * Ext JS Library 1.1.1
45811 * Copyright(c) 2006-2007, Ext JS, LLC.
45813 * Originally Released Under LGPL - original licence link has changed is not relivant.
45816 * <script type="text/javascript">
45820 * @class Roo.form.Layout
45821 * @extends Roo.Component
45822 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45824 * @param {Object} config Configuration options
45826 Roo.form.Layout = function(config){
45828 if (config.items) {
45829 xitems = config.items;
45830 delete config.items;
45832 Roo.form.Layout.superclass.constructor.call(this, config);
45834 Roo.each(xitems, this.addxtype, this);
45838 Roo.extend(Roo.form.Layout, Roo.Component, {
45840 * @cfg {String/Object} autoCreate
45841 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
45844 * @cfg {String/Object/Function} style
45845 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
45846 * a function which returns such a specification.
45849 * @cfg {String} labelAlign
45850 * Valid values are "left," "top" and "right" (defaults to "left")
45853 * @cfg {Number} labelWidth
45854 * Fixed width in pixels of all field labels (defaults to undefined)
45857 * @cfg {Boolean} clear
45858 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
45862 * @cfg {String} labelSeparator
45863 * The separator to use after field labels (defaults to ':')
45865 labelSeparator : ':',
45867 * @cfg {Boolean} hideLabels
45868 * True to suppress the display of field labels in this layout (defaults to false)
45870 hideLabels : false,
45873 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
45878 onRender : function(ct, position){
45879 if(this.el){ // from markup
45880 this.el = Roo.get(this.el);
45881 }else { // generate
45882 var cfg = this.getAutoCreate();
45883 this.el = ct.createChild(cfg, position);
45886 this.el.applyStyles(this.style);
45888 if(this.labelAlign){
45889 this.el.addClass('x-form-label-'+this.labelAlign);
45891 if(this.hideLabels){
45892 this.labelStyle = "display:none";
45893 this.elementStyle = "padding-left:0;";
45895 if(typeof this.labelWidth == 'number'){
45896 this.labelStyle = "width:"+this.labelWidth+"px;";
45897 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
45899 if(this.labelAlign == 'top'){
45900 this.labelStyle = "width:auto;";
45901 this.elementStyle = "padding-left:0;";
45904 var stack = this.stack;
45905 var slen = stack.length;
45907 if(!this.fieldTpl){
45908 var t = new Roo.Template(
45909 '<div class="x-form-item {5}">',
45910 '<label for="{0}" style="{2}">{1}{4}</label>',
45911 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45913 '</div><div class="x-form-clear-left"></div>'
45915 t.disableFormats = true;
45917 Roo.form.Layout.prototype.fieldTpl = t;
45919 for(var i = 0; i < slen; i++) {
45920 if(stack[i].isFormField){
45921 this.renderField(stack[i]);
45923 this.renderComponent(stack[i]);
45928 this.el.createChild({cls:'x-form-clear'});
45933 renderField : function(f){
45934 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
45937 f.labelStyle||this.labelStyle||'', //2
45938 this.elementStyle||'', //3
45939 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
45940 f.itemCls||this.itemCls||'' //5
45941 ], true).getPrevSibling());
45945 renderComponent : function(c){
45946 c.render(c.isLayout ? this.el : this.el.createChild());
45949 * Adds a object form elements (using the xtype property as the factory method.)
45950 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
45951 * @param {Object} config
45953 addxtype : function(o)
45955 // create the lement.
45956 o.form = this.form;
45957 var fe = Roo.factory(o, Roo.form);
45958 this.form.allItems.push(fe);
45959 this.stack.push(fe);
45961 if (fe.isFormField) {
45962 this.form.items.add(fe);
45970 * @class Roo.form.Column
45971 * @extends Roo.form.Layout
45972 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
45974 * @param {Object} config Configuration options
45976 Roo.form.Column = function(config){
45977 Roo.form.Column.superclass.constructor.call(this, config);
45980 Roo.extend(Roo.form.Column, Roo.form.Layout, {
45982 * @cfg {Number/String} width
45983 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45986 * @cfg {String/Object} autoCreate
45987 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
45991 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
45994 onRender : function(ct, position){
45995 Roo.form.Column.superclass.onRender.call(this, ct, position);
45997 this.el.setWidth(this.width);
46004 * @class Roo.form.Row
46005 * @extends Roo.form.Layout
46006 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46008 * @param {Object} config Configuration options
46012 Roo.form.Row = function(config){
46013 Roo.form.Row.superclass.constructor.call(this, config);
46016 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46018 * @cfg {Number/String} width
46019 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46022 * @cfg {Number/String} height
46023 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46025 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46029 onRender : function(ct, position){
46030 //console.log('row render');
46032 var t = new Roo.Template(
46033 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46034 '<label for="{0}" style="{2}">{1}{4}</label>',
46035 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46039 t.disableFormats = true;
46041 Roo.form.Layout.prototype.rowTpl = t;
46043 this.fieldTpl = this.rowTpl;
46045 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46046 var labelWidth = 100;
46048 if ((this.labelAlign != 'top')) {
46049 if (typeof this.labelWidth == 'number') {
46050 labelWidth = this.labelWidth
46052 this.padWidth = 20 + labelWidth;
46056 Roo.form.Column.superclass.onRender.call(this, ct, position);
46058 this.el.setWidth(this.width);
46061 this.el.setHeight(this.height);
46066 renderField : function(f){
46067 f.fieldEl = this.fieldTpl.append(this.el, [
46068 f.id, f.fieldLabel,
46069 f.labelStyle||this.labelStyle||'',
46070 this.elementStyle||'',
46071 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46072 f.itemCls||this.itemCls||'',
46073 f.width ? f.width + this.padWidth : 160 + this.padWidth
46080 * @class Roo.form.FieldSet
46081 * @extends Roo.form.Layout
46082 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46084 * @param {Object} config Configuration options
46086 Roo.form.FieldSet = function(config){
46087 Roo.form.FieldSet.superclass.constructor.call(this, config);
46090 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46092 * @cfg {String} legend
46093 * The text to display as the legend for the FieldSet (defaults to '')
46096 * @cfg {String/Object} autoCreate
46097 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46101 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46104 onRender : function(ct, position){
46105 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46107 this.setLegend(this.legend);
46112 setLegend : function(text){
46114 this.el.child('legend').update(text);
46119 * Ext JS Library 1.1.1
46120 * Copyright(c) 2006-2007, Ext JS, LLC.
46122 * Originally Released Under LGPL - original licence link has changed is not relivant.
46125 * <script type="text/javascript">
46128 * @class Roo.form.VTypes
46129 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46132 Roo.form.VTypes = function(){
46133 // closure these in so they are only created once.
46134 var alpha = /^[a-zA-Z_]+$/;
46135 var alphanum = /^[a-zA-Z0-9_]+$/;
46136 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46137 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46139 // All these messages and functions are configurable
46142 * The function used to validate email addresses
46143 * @param {String} value The email address
46145 'email' : function(v){
46146 return email.test(v);
46149 * The error text to display when the email validation function returns false
46152 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46154 * The keystroke filter mask to be applied on email input
46157 'emailMask' : /[a-z0-9_\.\-@]/i,
46160 * The function used to validate URLs
46161 * @param {String} value The URL
46163 'url' : function(v){
46164 return url.test(v);
46167 * The error text to display when the url validation function returns false
46170 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46173 * The function used to validate alpha values
46174 * @param {String} value The value
46176 'alpha' : function(v){
46177 return alpha.test(v);
46180 * The error text to display when the alpha validation function returns false
46183 'alphaText' : 'This field should only contain letters and _',
46185 * The keystroke filter mask to be applied on alpha input
46188 'alphaMask' : /[a-z_]/i,
46191 * The function used to validate alphanumeric values
46192 * @param {String} value The value
46194 'alphanum' : function(v){
46195 return alphanum.test(v);
46198 * The error text to display when the alphanumeric validation function returns false
46201 'alphanumText' : 'This field should only contain letters, numbers and _',
46203 * The keystroke filter mask to be applied on alphanumeric input
46206 'alphanumMask' : /[a-z0-9_]/i
46208 }();//<script type="text/javascript">
46211 * @class Roo.form.FCKeditor
46212 * @extends Roo.form.TextArea
46213 * Wrapper around the FCKEditor http://www.fckeditor.net
46215 * Creates a new FCKeditor
46216 * @param {Object} config Configuration options
46218 Roo.form.FCKeditor = function(config){
46219 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46222 * @event editorinit
46223 * Fired when the editor is initialized - you can add extra handlers here..
46224 * @param {FCKeditor} this
46225 * @param {Object} the FCK object.
46232 Roo.form.FCKeditor.editors = { };
46233 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46235 //defaultAutoCreate : {
46236 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46240 * @cfg {Object} fck options - see fck manual for details.
46245 * @cfg {Object} fck toolbar set (Basic or Default)
46247 toolbarSet : 'Basic',
46249 * @cfg {Object} fck BasePath
46251 basePath : '/fckeditor/',
46259 onRender : function(ct, position)
46262 this.defaultAutoCreate = {
46264 style:"width:300px;height:60px;",
46265 autocomplete: "off"
46268 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46271 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46272 if(this.preventScrollbars){
46273 this.el.setStyle("overflow", "hidden");
46275 this.el.setHeight(this.growMin);
46278 //console.log('onrender' + this.getId() );
46279 Roo.form.FCKeditor.editors[this.getId()] = this;
46282 this.replaceTextarea() ;
46286 getEditor : function() {
46287 return this.fckEditor;
46290 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46291 * @param {Mixed} value The value to set
46295 setValue : function(value)
46297 //console.log('setValue: ' + value);
46299 if(typeof(value) == 'undefined') { // not sure why this is happending...
46302 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46304 //if(!this.el || !this.getEditor()) {
46305 // this.value = value;
46306 //this.setValue.defer(100,this,[value]);
46310 if(!this.getEditor()) {
46314 this.getEditor().SetData(value);
46321 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46322 * @return {Mixed} value The field value
46324 getValue : function()
46327 if (this.frame && this.frame.dom.style.display == 'none') {
46328 return Roo.form.FCKeditor.superclass.getValue.call(this);
46331 if(!this.el || !this.getEditor()) {
46333 // this.getValue.defer(100,this);
46338 var value=this.getEditor().GetData();
46339 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46340 return Roo.form.FCKeditor.superclass.getValue.call(this);
46346 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46347 * @return {Mixed} value The field value
46349 getRawValue : function()
46351 if (this.frame && this.frame.dom.style.display == 'none') {
46352 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46355 if(!this.el || !this.getEditor()) {
46356 //this.getRawValue.defer(100,this);
46363 var value=this.getEditor().GetData();
46364 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46365 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46369 setSize : function(w,h) {
46373 //if (this.frame && this.frame.dom.style.display == 'none') {
46374 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46377 //if(!this.el || !this.getEditor()) {
46378 // this.setSize.defer(100,this, [w,h]);
46384 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46386 this.frame.dom.setAttribute('width', w);
46387 this.frame.dom.setAttribute('height', h);
46388 this.frame.setSize(w,h);
46392 toggleSourceEdit : function(value) {
46396 this.el.dom.style.display = value ? '' : 'none';
46397 this.frame.dom.style.display = value ? 'none' : '';
46402 focus: function(tag)
46404 if (this.frame.dom.style.display == 'none') {
46405 return Roo.form.FCKeditor.superclass.focus.call(this);
46407 if(!this.el || !this.getEditor()) {
46408 this.focus.defer(100,this, [tag]);
46415 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46416 this.getEditor().Focus();
46418 if (!this.getEditor().Selection.GetSelection()) {
46419 this.focus.defer(100,this, [tag]);
46424 var r = this.getEditor().EditorDocument.createRange();
46425 r.setStart(tgs[0],0);
46426 r.setEnd(tgs[0],0);
46427 this.getEditor().Selection.GetSelection().removeAllRanges();
46428 this.getEditor().Selection.GetSelection().addRange(r);
46429 this.getEditor().Focus();
46436 replaceTextarea : function()
46438 if ( document.getElementById( this.getId() + '___Frame' ) )
46440 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46442 // We must check the elements firstly using the Id and then the name.
46443 var oTextarea = document.getElementById( this.getId() );
46445 var colElementsByName = document.getElementsByName( this.getId() ) ;
46447 oTextarea.style.display = 'none' ;
46449 if ( oTextarea.tabIndex ) {
46450 this.TabIndex = oTextarea.tabIndex ;
46453 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46454 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46455 this.frame = Roo.get(this.getId() + '___Frame')
46458 _getConfigHtml : function()
46462 for ( var o in this.fckconfig ) {
46463 sConfig += sConfig.length > 0 ? '&' : '';
46464 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
46467 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
46471 _getIFrameHtml : function()
46473 var sFile = 'fckeditor.html' ;
46474 /* no idea what this is about..
46477 if ( (/fcksource=true/i).test( window.top.location.search ) )
46478 sFile = 'fckeditor.original.html' ;
46483 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
46484 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
46487 var html = '<iframe id="' + this.getId() +
46488 '___Frame" src="' + sLink +
46489 '" width="' + this.width +
46490 '" height="' + this.height + '"' +
46491 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
46492 ' frameborder="0" scrolling="no"></iframe>' ;
46497 _insertHtmlBefore : function( html, element )
46499 if ( element.insertAdjacentHTML ) {
46501 element.insertAdjacentHTML( 'beforeBegin', html ) ;
46503 var oRange = document.createRange() ;
46504 oRange.setStartBefore( element ) ;
46505 var oFragment = oRange.createContextualFragment( html );
46506 element.parentNode.insertBefore( oFragment, element ) ;
46519 //Roo.reg('fckeditor', Roo.form.FCKeditor);
46521 function FCKeditor_OnComplete(editorInstance){
46522 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
46523 f.fckEditor = editorInstance;
46524 //console.log("loaded");
46525 f.fireEvent('editorinit', f, editorInstance);
46545 //<script type="text/javascript">
46547 * @class Roo.form.GridField
46548 * @extends Roo.form.Field
46549 * Embed a grid (or editable grid into a form)
46552 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
46554 * xgrid.store = Roo.data.Store
46555 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
46556 * xgrid.store.reader = Roo.data.JsonReader
46560 * Creates a new GridField
46561 * @param {Object} config Configuration options
46563 Roo.form.GridField = function(config){
46564 Roo.form.GridField.superclass.constructor.call(this, config);
46568 Roo.extend(Roo.form.GridField, Roo.form.Field, {
46570 * @cfg {Number} width - used to restrict width of grid..
46574 * @cfg {Number} height - used to restrict height of grid..
46578 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
46584 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46585 * {tag: "input", type: "checkbox", autocomplete: "off"})
46587 // defaultAutoCreate : { tag: 'div' },
46588 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46590 * @cfg {String} addTitle Text to include for adding a title.
46594 onResize : function(){
46595 Roo.form.Field.superclass.onResize.apply(this, arguments);
46598 initEvents : function(){
46599 // Roo.form.Checkbox.superclass.initEvents.call(this);
46600 // has no events...
46605 getResizeEl : function(){
46609 getPositionEl : function(){
46614 onRender : function(ct, position){
46616 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
46617 var style = this.style;
46620 Roo.form.GridField.superclass.onRender.call(this, ct, position);
46621 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
46622 this.viewEl = this.wrap.createChild({ tag: 'div' });
46624 this.viewEl.applyStyles(style);
46627 this.viewEl.setWidth(this.width);
46630 this.viewEl.setHeight(this.height);
46632 //if(this.inputValue !== undefined){
46633 //this.setValue(this.value);
46636 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
46639 this.grid.render();
46640 this.grid.getDataSource().on('remove', this.refreshValue, this);
46641 this.grid.getDataSource().on('update', this.refreshValue, this);
46642 this.grid.on('afteredit', this.refreshValue, this);
46648 * Sets the value of the item.
46649 * @param {String} either an object or a string..
46651 setValue : function(v){
46653 v = v || []; // empty set..
46654 // this does not seem smart - it really only affects memoryproxy grids..
46655 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
46656 var ds = this.grid.getDataSource();
46657 // assumes a json reader..
46659 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
46660 ds.loadData( data);
46662 // clear selection so it does not get stale.
46663 if (this.grid.sm) {
46664 this.grid.sm.clearSelections();
46667 Roo.form.GridField.superclass.setValue.call(this, v);
46668 this.refreshValue();
46669 // should load data in the grid really....
46673 refreshValue: function() {
46675 this.grid.getDataSource().each(function(r) {
46678 this.el.dom.value = Roo.encode(val);
46686 * Ext JS Library 1.1.1
46687 * Copyright(c) 2006-2007, Ext JS, LLC.
46689 * Originally Released Under LGPL - original licence link has changed is not relivant.
46692 * <script type="text/javascript">
46695 * @class Roo.form.DisplayField
46696 * @extends Roo.form.Field
46697 * A generic Field to display non-editable data.
46699 * Creates a new Display Field item.
46700 * @param {Object} config Configuration options
46702 Roo.form.DisplayField = function(config){
46703 Roo.form.DisplayField.superclass.constructor.call(this, config);
46707 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
46708 inputType: 'hidden',
46714 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46716 focusClass : undefined,
46718 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46720 fieldClass: 'x-form-field',
46723 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
46725 valueRenderer: undefined,
46729 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46730 * {tag: "input", type: "checkbox", autocomplete: "off"})
46733 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46735 onResize : function(){
46736 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
46740 initEvents : function(){
46741 // Roo.form.Checkbox.superclass.initEvents.call(this);
46742 // has no events...
46747 getResizeEl : function(){
46751 getPositionEl : function(){
46756 onRender : function(ct, position){
46758 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
46759 //if(this.inputValue !== undefined){
46760 this.wrap = this.el.wrap();
46762 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
46764 if (this.bodyStyle) {
46765 this.viewEl.applyStyles(this.bodyStyle);
46767 //this.viewEl.setStyle('padding', '2px');
46769 this.setValue(this.value);
46774 initValue : Roo.emptyFn,
46779 onClick : function(){
46784 * Sets the checked state of the checkbox.
46785 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
46787 setValue : function(v){
46789 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
46790 // this might be called before we have a dom element..
46791 if (!this.viewEl) {
46794 this.viewEl.dom.innerHTML = html;
46795 Roo.form.DisplayField.superclass.setValue.call(this, v);
46805 * @class Roo.form.DayPicker
46806 * @extends Roo.form.Field
46807 * A Day picker show [M] [T] [W] ....
46809 * Creates a new Day Picker
46810 * @param {Object} config Configuration options
46812 Roo.form.DayPicker= function(config){
46813 Roo.form.DayPicker.superclass.constructor.call(this, config);
46817 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
46819 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46821 focusClass : undefined,
46823 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46825 fieldClass: "x-form-field",
46828 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46829 * {tag: "input", type: "checkbox", autocomplete: "off"})
46831 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
46834 actionMode : 'viewEl',
46838 inputType : 'hidden',
46841 inputElement: false, // real input element?
46842 basedOn: false, // ????
46844 isFormField: true, // not sure where this is needed!!!!
46846 onResize : function(){
46847 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
46848 if(!this.boxLabel){
46849 this.el.alignTo(this.wrap, 'c-c');
46853 initEvents : function(){
46854 Roo.form.Checkbox.superclass.initEvents.call(this);
46855 this.el.on("click", this.onClick, this);
46856 this.el.on("change", this.onClick, this);
46860 getResizeEl : function(){
46864 getPositionEl : function(){
46870 onRender : function(ct, position){
46871 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
46873 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
46875 var r1 = '<table><tr>';
46876 var r2 = '<tr class="x-form-daypick-icons">';
46877 for (var i=0; i < 7; i++) {
46878 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
46879 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
46882 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
46883 viewEl.select('img').on('click', this.onClick, this);
46884 this.viewEl = viewEl;
46887 // this will not work on Chrome!!!
46888 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
46889 this.el.on('propertychange', this.setFromHidden, this); //ie
46897 initValue : Roo.emptyFn,
46900 * Returns the checked state of the checkbox.
46901 * @return {Boolean} True if checked, else false
46903 getValue : function(){
46904 return this.el.dom.value;
46909 onClick : function(e){
46910 //this.setChecked(!this.checked);
46911 Roo.get(e.target).toggleClass('x-menu-item-checked');
46912 this.refreshValue();
46913 //if(this.el.dom.checked != this.checked){
46914 // this.setValue(this.el.dom.checked);
46919 refreshValue : function()
46922 this.viewEl.select('img',true).each(function(e,i,n) {
46923 val += e.is(".x-menu-item-checked") ? String(n) : '';
46925 this.setValue(val, true);
46929 * Sets the checked state of the checkbox.
46930 * On is always based on a string comparison between inputValue and the param.
46931 * @param {Boolean/String} value - the value to set
46932 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
46934 setValue : function(v,suppressEvent){
46935 if (!this.el.dom) {
46938 var old = this.el.dom.value ;
46939 this.el.dom.value = v;
46940 if (suppressEvent) {
46944 // update display..
46945 this.viewEl.select('img',true).each(function(e,i,n) {
46947 var on = e.is(".x-menu-item-checked");
46948 var newv = v.indexOf(String(n)) > -1;
46950 e.toggleClass('x-menu-item-checked');
46956 this.fireEvent('change', this, v, old);
46961 // handle setting of hidden value by some other method!!?!?
46962 setFromHidden: function()
46967 //console.log("SET FROM HIDDEN");
46968 //alert('setFrom hidden');
46969 this.setValue(this.el.dom.value);
46972 onDestroy : function()
46975 Roo.get(this.viewEl).remove();
46978 Roo.form.DayPicker.superclass.onDestroy.call(this);
46982 * RooJS Library 1.1.1
46983 * Copyright(c) 2008-2011 Alan Knowles
46990 * @class Roo.form.ComboCheck
46991 * @extends Roo.form.ComboBox
46992 * A combobox for multiple select items.
46994 * FIXME - could do with a reset button..
46997 * Create a new ComboCheck
46998 * @param {Object} config Configuration options
47000 Roo.form.ComboCheck = function(config){
47001 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47002 // should verify some data...
47004 // hiddenName = required..
47005 // displayField = required
47006 // valudField == required
47007 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47009 Roo.each(req, function(e) {
47010 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47011 throw "Roo.form.ComboCheck : missing value for: " + e;
47018 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47023 selectedClass: 'x-menu-item-checked',
47026 onRender : function(ct, position){
47032 var cls = 'x-combo-list';
47035 this.tpl = new Roo.Template({
47036 html : '<div class="'+cls+'-item x-menu-check-item">' +
47037 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47038 '<span>{' + this.displayField + '}</span>' +
47045 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47046 this.view.singleSelect = false;
47047 this.view.multiSelect = true;
47048 this.view.toggleSelect = true;
47049 this.pageTb.add(new Roo.Toolbar.Fill(), {
47052 handler: function()
47059 onViewOver : function(e, t){
47065 onViewClick : function(doFocus,index){
47069 select: function () {
47070 //Roo.log("SELECT CALLED");
47073 selectByValue : function(xv, scrollIntoView){
47074 var ar = this.getValueArray();
47077 Roo.each(ar, function(v) {
47078 if(v === undefined || v === null){
47081 var r = this.findRecord(this.valueField, v);
47083 sels.push(this.store.indexOf(r))
47087 this.view.select(sels);
47093 onSelect : function(record, index){
47094 // Roo.log("onselect Called");
47095 // this is only called by the clear button now..
47096 this.view.clearSelections();
47097 this.setValue('[]');
47098 if (this.value != this.valueBefore) {
47099 this.fireEvent('change', this, this.value, this.valueBefore);
47100 this.valueBefore = this.value;
47103 getValueArray : function()
47108 //Roo.log(this.value);
47109 if (typeof(this.value) == 'undefined') {
47112 var ar = Roo.decode(this.value);
47113 return ar instanceof Array ? ar : []; //?? valid?
47116 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47121 expand : function ()
47124 Roo.form.ComboCheck.superclass.expand.call(this);
47125 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47126 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47131 collapse : function(){
47132 Roo.form.ComboCheck.superclass.collapse.call(this);
47133 var sl = this.view.getSelectedIndexes();
47134 var st = this.store;
47138 Roo.each(sl, function(i) {
47140 nv.push(r.get(this.valueField));
47142 this.setValue(Roo.encode(nv));
47143 if (this.value != this.valueBefore) {
47145 this.fireEvent('change', this, this.value, this.valueBefore);
47146 this.valueBefore = this.value;
47151 setValue : function(v){
47155 var vals = this.getValueArray();
47157 Roo.each(vals, function(k) {
47158 var r = this.findRecord(this.valueField, k);
47160 tv.push(r.data[this.displayField]);
47161 }else if(this.valueNotFoundText !== undefined){
47162 tv.push( this.valueNotFoundText );
47167 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47168 this.hiddenField.value = v;
47174 * Ext JS Library 1.1.1
47175 * Copyright(c) 2006-2007, Ext JS, LLC.
47177 * Originally Released Under LGPL - original licence link has changed is not relivant.
47180 * <script type="text/javascript">
47184 * @class Roo.form.Signature
47185 * @extends Roo.form.Field
47189 * @param {Object} config Configuration options
47192 Roo.form.Signature = function(config){
47193 Roo.form.Signature.superclass.constructor.call(this, config);
47195 this.addEvents({// not in used??
47198 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47199 * @param {Roo.form.Signature} combo This combo box
47204 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47205 * @param {Roo.form.ComboBox} combo This combo box
47206 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47212 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47214 * @cfg {Object} labels Label to use when rendering a form.
47218 * confirm : "Confirm"
47223 confirm : "Confirm"
47226 * @cfg {Number} width The signature panel width (defaults to 300)
47230 * @cfg {Number} height The signature panel height (defaults to 100)
47234 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47236 allowBlank : false,
47239 // {Object} signPanel The signature SVG panel element (defaults to {})
47241 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47242 isMouseDown : false,
47243 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47244 isConfirmed : false,
47245 // {String} signatureTmp SVG mapping string (defaults to empty string)
47249 defaultAutoCreate : { // modified by initCompnoent..
47255 onRender : function(ct, position){
47257 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47259 this.wrap = this.el.wrap({
47260 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47263 this.createToolbar(this);
47264 this.signPanel = this.wrap.createChild({
47266 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47270 this.svgID = Roo.id();
47271 this.svgEl = this.signPanel.createChild({
47272 xmlns : 'http://www.w3.org/2000/svg',
47274 id : this.svgID + "-svg",
47276 height: this.height,
47277 viewBox: '0 0 '+this.width+' '+this.height,
47281 id: this.svgID + "-svg-r",
47283 height: this.height,
47288 id: this.svgID + "-svg-l",
47290 y1: (this.height*0.8), // start set the line in 80% of height
47291 x2: this.width, // end
47292 y2: (this.height*0.8), // end set the line in 80% of height
47294 'stroke-width': "1",
47295 'stroke-dasharray': "3",
47296 'shape-rendering': "crispEdges",
47297 'pointer-events': "none"
47301 id: this.svgID + "-svg-p",
47303 'stroke-width': "3",
47305 'pointer-events': 'none'
47310 this.svgBox = this.svgEl.dom.getScreenCTM();
47312 createSVG : function(){
47313 var svg = this.signPanel;
47314 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47317 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47318 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47319 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47320 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47321 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47322 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47323 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47326 isTouchEvent : function(e){
47327 return e.type.match(/^touch/);
47329 getCoords : function (e) {
47330 var pt = this.svgEl.dom.createSVGPoint();
47333 if (this.isTouchEvent(e)) {
47334 pt.x = e.targetTouches[0].clientX
47335 pt.y = e.targetTouches[0].clientY;
47337 var a = this.svgEl.dom.getScreenCTM();
47338 var b = a.inverse();
47339 var mx = pt.matrixTransform(b);
47340 return mx.x + ',' + mx.y;
47342 //mouse event headler
47343 down : function (e) {
47344 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47345 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47347 this.isMouseDown = true;
47349 e.preventDefault();
47351 move : function (e) {
47352 if (this.isMouseDown) {
47353 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47354 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47357 e.preventDefault();
47359 up : function (e) {
47360 this.isMouseDown = false;
47361 var sp = this.signatureTmp.split(' ');
47364 if(!sp[sp.length-2].match(/^L/)){
47368 this.signatureTmp = sp.join(" ");
47371 if(this.getValue() != this.signatureTmp){
47372 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47373 this.isConfirmed = false;
47375 e.preventDefault();
47379 * Protected method that will not generally be called directly. It
47380 * is called when the editor creates its toolbar. Override this method if you need to
47381 * add custom toolbar buttons.
47382 * @param {HtmlEditor} editor
47384 createToolbar : function(editor){
47385 function btn(id, toggle, handler){
47386 var xid = fid + '-'+ id ;
47390 cls : 'x-btn-icon x-edit-'+id,
47391 enableToggle:toggle !== false,
47392 scope: editor, // was editor...
47393 handler:handler||editor.relayBtnCmd,
47394 clickEvent:'mousedown',
47395 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47401 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47405 cls : ' x-signature-btn x-signature-'+id,
47406 scope: editor, // was editor...
47407 handler: this.reset,
47408 clickEvent:'mousedown',
47409 text: this.labels.clear
47416 cls : ' x-signature-btn x-signature-'+id,
47417 scope: editor, // was editor...
47418 handler: this.confirmHandler,
47419 clickEvent:'mousedown',
47420 text: this.labels.confirm
47427 * when user is clicked confirm then show this image.....
47429 * @return {String} Image Data URI
47431 getImageDataURI : function(){
47432 var svg = this.svgEl.dom.parentNode.innerHTML;
47433 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47438 * @return {Boolean} this.isConfirmed
47440 getConfirmed : function(){
47441 return this.isConfirmed;
47445 * @return {Number} this.width
47447 getWidth : function(){
47452 * @return {Number} this.height
47454 getHeight : function(){
47455 return this.height;
47458 getSignature : function(){
47459 return this.signatureTmp;
47462 reset : function(){
47463 this.signatureTmp = '';
47464 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47465 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
47466 this.isConfirmed = false;
47467 Roo.form.Signature.superclass.reset.call(this);
47469 setSignature : function(s){
47470 this.signatureTmp = s;
47471 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47472 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
47474 this.isConfirmed = false;
47475 Roo.form.Signature.superclass.reset.call(this);
47478 // Roo.log(this.signPanel.dom.contentWindow.up())
47481 setConfirmed : function(){
47485 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
47488 confirmHandler : function(){
47489 if(!this.getSignature()){
47493 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
47494 this.setValue(this.getSignature());
47495 this.isConfirmed = true;
47497 this.fireEvent('confirm', this);
47500 // Subclasses should provide the validation implementation by overriding this
47501 validateValue : function(value){
47502 if(this.allowBlank){
47506 if(this.isConfirmed){
47513 * Ext JS Library 1.1.1
47514 * Copyright(c) 2006-2007, Ext JS, LLC.
47516 * Originally Released Under LGPL - original licence link has changed is not relivant.
47519 * <script type="text/javascript">
47524 * @class Roo.form.ComboBox
47525 * @extends Roo.form.TriggerField
47526 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
47528 * Create a new ComboBox.
47529 * @param {Object} config Configuration options
47531 Roo.form.Select = function(config){
47532 Roo.form.Select.superclass.constructor.call(this, config);
47536 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
47538 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
47541 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
47542 * rendering into an Roo.Editor, defaults to false)
47545 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
47546 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
47549 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
47552 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
47553 * the dropdown list (defaults to undefined, with no header element)
47557 * @cfg {String/Roo.Template} tpl The template to use to render the output
47561 defaultAutoCreate : {tag: "select" },
47563 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
47565 listWidth: undefined,
47567 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
47568 * mode = 'remote' or 'text' if mode = 'local')
47570 displayField: undefined,
47572 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
47573 * mode = 'remote' or 'value' if mode = 'local').
47574 * Note: use of a valueField requires the user make a selection
47575 * in order for a value to be mapped.
47577 valueField: undefined,
47581 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
47582 * field's data value (defaults to the underlying DOM element's name)
47584 hiddenName: undefined,
47586 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
47590 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
47592 selectedClass: 'x-combo-selected',
47594 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
47595 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
47596 * which displays a downward arrow icon).
47598 triggerClass : 'x-form-arrow-trigger',
47600 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
47604 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
47605 * anchor positions (defaults to 'tl-bl')
47607 listAlign: 'tl-bl?',
47609 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
47613 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
47614 * query specified by the allQuery config option (defaults to 'query')
47616 triggerAction: 'query',
47618 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
47619 * (defaults to 4, does not apply if editable = false)
47623 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
47624 * delay (typeAheadDelay) if it matches a known value (defaults to false)
47628 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
47629 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
47633 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
47634 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
47638 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
47639 * when editable = true (defaults to false)
47641 selectOnFocus:false,
47643 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
47645 queryParam: 'query',
47647 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
47648 * when mode = 'remote' (defaults to 'Loading...')
47650 loadingText: 'Loading...',
47652 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
47656 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
47660 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
47661 * traditional select (defaults to true)
47665 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
47669 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
47673 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
47674 * listWidth has a higher value)
47678 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
47679 * allow the user to set arbitrary text into the field (defaults to false)
47681 forceSelection:false,
47683 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
47684 * if typeAhead = true (defaults to 250)
47686 typeAheadDelay : 250,
47688 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
47689 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
47691 valueNotFoundText : undefined,
47694 * @cfg {String} defaultValue The value displayed after loading the store.
47699 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
47701 blockFocus : false,
47704 * @cfg {Boolean} disableClear Disable showing of clear button.
47706 disableClear : false,
47708 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
47710 alwaysQuery : false,
47716 // element that contains real text value.. (when hidden is used..)
47719 onRender : function(ct, position){
47720 Roo.form.Field.prototype.onRender.call(this, ct, position);
47723 this.store.on('beforeload', this.onBeforeLoad, this);
47724 this.store.on('load', this.onLoad, this);
47725 this.store.on('loadexception', this.onLoadException, this);
47726 this.store.load({});
47734 initEvents : function(){
47735 //Roo.form.ComboBox.superclass.initEvents.call(this);
47739 onDestroy : function(){
47742 this.store.un('beforeload', this.onBeforeLoad, this);
47743 this.store.un('load', this.onLoad, this);
47744 this.store.un('loadexception', this.onLoadException, this);
47746 //Roo.form.ComboBox.superclass.onDestroy.call(this);
47750 fireKey : function(e){
47751 if(e.isNavKeyPress() && !this.list.isVisible()){
47752 this.fireEvent("specialkey", this, e);
47757 onResize: function(w, h){
47765 * Allow or prevent the user from directly editing the field text. If false is passed,
47766 * the user will only be able to select from the items defined in the dropdown list. This method
47767 * is the runtime equivalent of setting the 'editable' config option at config time.
47768 * @param {Boolean} value True to allow the user to directly edit the field text
47770 setEditable : function(value){
47775 onBeforeLoad : function(){
47777 Roo.log("Select before load");
47780 this.innerList.update(this.loadingText ?
47781 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
47782 //this.restrictHeight();
47783 this.selectedIndex = -1;
47787 onLoad : function(){
47790 var dom = this.el.dom;
47791 dom.innerHTML = '';
47792 var od = dom.ownerDocument;
47794 if (this.emptyText) {
47795 var op = od.createElement('option');
47796 op.setAttribute('value', '');
47797 op.innerHTML = String.format('{0}', this.emptyText);
47798 dom.appendChild(op);
47800 if(this.store.getCount() > 0){
47802 var vf = this.valueField;
47803 var df = this.displayField;
47804 this.store.data.each(function(r) {
47805 // which colmsn to use... testing - cdoe / title..
47806 var op = od.createElement('option');
47807 op.setAttribute('value', r.data[vf]);
47808 op.innerHTML = String.format('{0}', r.data[df]);
47809 dom.appendChild(op);
47811 if (typeof(this.defaultValue != 'undefined')) {
47812 this.setValue(this.defaultValue);
47817 //this.onEmptyResults();
47822 onLoadException : function()
47824 dom.innerHTML = '';
47826 Roo.log("Select on load exception");
47830 Roo.log(this.store.reader.jsonData);
47831 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
47832 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
47838 onTypeAhead : function(){
47843 onSelect : function(record, index){
47844 Roo.log('on select?');
47846 if(this.fireEvent('beforeselect', this, record, index) !== false){
47847 this.setFromData(index > -1 ? record.data : false);
47849 this.fireEvent('select', this, record, index);
47854 * Returns the currently selected field value or empty string if no value is set.
47855 * @return {String} value The selected value
47857 getValue : function(){
47858 var dom = this.el.dom;
47859 this.value = dom.options[dom.selectedIndex].value;
47865 * Clears any text/value currently set in the field
47867 clearValue : function(){
47869 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
47874 * Sets the specified value into the field. If the value finds a match, the corresponding record text
47875 * will be displayed in the field. If the value does not match the data value of an existing item,
47876 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
47877 * Otherwise the field will be blank (although the value will still be set).
47878 * @param {String} value The value to match
47880 setValue : function(v){
47881 var d = this.el.dom;
47882 for (var i =0; i < d.options.length;i++) {
47883 if (v == d.options[i].value) {
47884 d.selectedIndex = i;
47892 * @property {Object} the last set data for the element
47897 * Sets the value of the field based on a object which is related to the record format for the store.
47898 * @param {Object} value the value to set as. or false on reset?
47900 setFromData : function(o){
47901 Roo.log('setfrom data?');
47907 reset : function(){
47911 findRecord : function(prop, value){
47916 if(this.store.getCount() > 0){
47917 this.store.each(function(r){
47918 if(r.data[prop] == value){
47928 getName: function()
47930 // returns hidden if it's set..
47931 if (!this.rendered) {return ''};
47932 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
47940 onEmptyResults : function(){
47941 Roo.log('empty results');
47946 * Returns true if the dropdown list is expanded, else false.
47948 isExpanded : function(){
47953 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
47954 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47955 * @param {String} value The data value of the item to select
47956 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47957 * selected item if it is not currently in view (defaults to true)
47958 * @return {Boolean} True if the value matched an item in the list, else false
47960 selectByValue : function(v, scrollIntoView){
47961 Roo.log('select By Value');
47964 if(v !== undefined && v !== null){
47965 var r = this.findRecord(this.valueField || this.displayField, v);
47967 this.select(this.store.indexOf(r), scrollIntoView);
47975 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
47976 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47977 * @param {Number} index The zero-based index of the list item to select
47978 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47979 * selected item if it is not currently in view (defaults to true)
47981 select : function(index, scrollIntoView){
47982 Roo.log('select ');
47985 this.selectedIndex = index;
47986 this.view.select(index);
47987 if(scrollIntoView !== false){
47988 var el = this.view.getNode(index);
47990 this.innerList.scrollChildIntoView(el, false);
47998 validateBlur : function(){
48005 initQuery : function(){
48006 this.doQuery(this.getRawValue());
48010 doForce : function(){
48011 if(this.el.dom.value.length > 0){
48012 this.el.dom.value =
48013 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48019 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48020 * query allowing the query action to be canceled if needed.
48021 * @param {String} query The SQL query to execute
48022 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48023 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48024 * saved in the current store (defaults to false)
48026 doQuery : function(q, forceAll){
48028 Roo.log('doQuery?');
48029 if(q === undefined || q === null){
48034 forceAll: forceAll,
48038 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48042 forceAll = qe.forceAll;
48043 if(forceAll === true || (q.length >= this.minChars)){
48044 if(this.lastQuery != q || this.alwaysQuery){
48045 this.lastQuery = q;
48046 if(this.mode == 'local'){
48047 this.selectedIndex = -1;
48049 this.store.clearFilter();
48051 this.store.filter(this.displayField, q);
48055 this.store.baseParams[this.queryParam] = q;
48057 params: this.getParams(q)
48062 this.selectedIndex = -1;
48069 getParams : function(q){
48071 //p[this.queryParam] = q;
48074 p.limit = this.pageSize;
48080 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48082 collapse : function(){
48087 collapseIf : function(e){
48092 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48094 expand : function(){
48102 * @cfg {Boolean} grow
48106 * @cfg {Number} growMin
48110 * @cfg {Number} growMax
48118 setWidth : function()
48122 getResizeEl : function(){
48125 });//<script type="text/javasscript">
48129 * @class Roo.DDView
48130 * A DnD enabled version of Roo.View.
48131 * @param {Element/String} container The Element in which to create the View.
48132 * @param {String} tpl The template string used to create the markup for each element of the View
48133 * @param {Object} config The configuration properties. These include all the config options of
48134 * {@link Roo.View} plus some specific to this class.<br>
48136 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48137 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48139 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48140 .x-view-drag-insert-above {
48141 border-top:1px dotted #3366cc;
48143 .x-view-drag-insert-below {
48144 border-bottom:1px dotted #3366cc;
48150 Roo.DDView = function(container, tpl, config) {
48151 Roo.DDView.superclass.constructor.apply(this, arguments);
48152 this.getEl().setStyle("outline", "0px none");
48153 this.getEl().unselectable();
48154 if (this.dragGroup) {
48155 this.setDraggable(this.dragGroup.split(","));
48157 if (this.dropGroup) {
48158 this.setDroppable(this.dropGroup.split(","));
48160 if (this.deletable) {
48161 this.setDeletable();
48163 this.isDirtyFlag = false;
48169 Roo.extend(Roo.DDView, Roo.View, {
48170 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48171 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48172 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48173 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48177 reset: Roo.emptyFn,
48179 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48181 validate: function() {
48185 destroy: function() {
48186 this.purgeListeners();
48187 this.getEl.removeAllListeners();
48188 this.getEl().remove();
48189 if (this.dragZone) {
48190 if (this.dragZone.destroy) {
48191 this.dragZone.destroy();
48194 if (this.dropZone) {
48195 if (this.dropZone.destroy) {
48196 this.dropZone.destroy();
48201 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48202 getName: function() {
48206 /** Loads the View from a JSON string representing the Records to put into the Store. */
48207 setValue: function(v) {
48209 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48212 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48213 this.store.proxy = new Roo.data.MemoryProxy(data);
48217 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48218 getValue: function() {
48220 this.store.each(function(rec) {
48221 result += rec.id + ',';
48223 return result.substr(0, result.length - 1) + ')';
48226 getIds: function() {
48227 var i = 0, result = new Array(this.store.getCount());
48228 this.store.each(function(rec) {
48229 result[i++] = rec.id;
48234 isDirty: function() {
48235 return this.isDirtyFlag;
48239 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48240 * whole Element becomes the target, and this causes the drop gesture to append.
48242 getTargetFromEvent : function(e) {
48243 var target = e.getTarget();
48244 while ((target !== null) && (target.parentNode != this.el.dom)) {
48245 target = target.parentNode;
48248 target = this.el.dom.lastChild || this.el.dom;
48254 * Create the drag data which consists of an object which has the property "ddel" as
48255 * the drag proxy element.
48257 getDragData : function(e) {
48258 var target = this.findItemFromChild(e.getTarget());
48260 this.handleSelection(e);
48261 var selNodes = this.getSelectedNodes();
48264 copy: this.copy || (this.allowCopy && e.ctrlKey),
48268 var selectedIndices = this.getSelectedIndexes();
48269 for (var i = 0; i < selectedIndices.length; i++) {
48270 dragData.records.push(this.store.getAt(selectedIndices[i]));
48272 if (selNodes.length == 1) {
48273 dragData.ddel = target.cloneNode(true); // the div element
48275 var div = document.createElement('div'); // create the multi element drag "ghost"
48276 div.className = 'multi-proxy';
48277 for (var i = 0, len = selNodes.length; i < len; i++) {
48278 div.appendChild(selNodes[i].cloneNode(true));
48280 dragData.ddel = div;
48282 //console.log(dragData)
48283 //console.log(dragData.ddel.innerHTML)
48286 //console.log('nodragData')
48290 /** Specify to which ddGroup items in this DDView may be dragged. */
48291 setDraggable: function(ddGroup) {
48292 if (ddGroup instanceof Array) {
48293 Roo.each(ddGroup, this.setDraggable, this);
48296 if (this.dragZone) {
48297 this.dragZone.addToGroup(ddGroup);
48299 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48300 containerScroll: true,
48304 // Draggability implies selection. DragZone's mousedown selects the element.
48305 if (!this.multiSelect) { this.singleSelect = true; }
48307 // Wire the DragZone's handlers up to methods in *this*
48308 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48312 /** Specify from which ddGroup this DDView accepts drops. */
48313 setDroppable: function(ddGroup) {
48314 if (ddGroup instanceof Array) {
48315 Roo.each(ddGroup, this.setDroppable, this);
48318 if (this.dropZone) {
48319 this.dropZone.addToGroup(ddGroup);
48321 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48322 containerScroll: true,
48326 // Wire the DropZone's handlers up to methods in *this*
48327 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48328 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48329 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48330 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48331 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48335 /** Decide whether to drop above or below a View node. */
48336 getDropPoint : function(e, n, dd){
48337 if (n == this.el.dom) { return "above"; }
48338 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48339 var c = t + (b - t) / 2;
48340 var y = Roo.lib.Event.getPageY(e);
48348 onNodeEnter : function(n, dd, e, data){
48352 onNodeOver : function(n, dd, e, data){
48353 var pt = this.getDropPoint(e, n, dd);
48354 // set the insert point style on the target node
48355 var dragElClass = this.dropNotAllowed;
48358 if (pt == "above"){
48359 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48360 targetElClass = "x-view-drag-insert-above";
48362 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48363 targetElClass = "x-view-drag-insert-below";
48365 if (this.lastInsertClass != targetElClass){
48366 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48367 this.lastInsertClass = targetElClass;
48370 return dragElClass;
48373 onNodeOut : function(n, dd, e, data){
48374 this.removeDropIndicators(n);
48377 onNodeDrop : function(n, dd, e, data){
48378 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48381 var pt = this.getDropPoint(e, n, dd);
48382 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48383 if (pt == "below") { insertAt++; }
48384 for (var i = 0; i < data.records.length; i++) {
48385 var r = data.records[i];
48386 var dup = this.store.getById(r.id);
48387 if (dup && (dd != this.dragZone)) {
48388 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48391 this.store.insert(insertAt++, r.copy());
48393 data.source.isDirtyFlag = true;
48395 this.store.insert(insertAt++, r);
48397 this.isDirtyFlag = true;
48400 this.dragZone.cachedTarget = null;
48404 removeDropIndicators : function(n){
48406 Roo.fly(n).removeClass([
48407 "x-view-drag-insert-above",
48408 "x-view-drag-insert-below"]);
48409 this.lastInsertClass = "_noclass";
48414 * Utility method. Add a delete option to the DDView's context menu.
48415 * @param {String} imageUrl The URL of the "delete" icon image.
48417 setDeletable: function(imageUrl) {
48418 if (!this.singleSelect && !this.multiSelect) {
48419 this.singleSelect = true;
48421 var c = this.getContextMenu();
48422 this.contextMenu.on("itemclick", function(item) {
48425 this.remove(this.getSelectedIndexes());
48429 this.contextMenu.add({
48436 /** Return the context menu for this DDView. */
48437 getContextMenu: function() {
48438 if (!this.contextMenu) {
48439 // Create the View's context menu
48440 this.contextMenu = new Roo.menu.Menu({
48441 id: this.id + "-contextmenu"
48443 this.el.on("contextmenu", this.showContextMenu, this);
48445 return this.contextMenu;
48448 disableContextMenu: function() {
48449 if (this.contextMenu) {
48450 this.el.un("contextmenu", this.showContextMenu, this);
48454 showContextMenu: function(e, item) {
48455 item = this.findItemFromChild(e.getTarget());
48458 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
48459 this.contextMenu.showAt(e.getXY());
48464 * Remove {@link Roo.data.Record}s at the specified indices.
48465 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
48467 remove: function(selectedIndices) {
48468 selectedIndices = [].concat(selectedIndices);
48469 for (var i = 0; i < selectedIndices.length; i++) {
48470 var rec = this.store.getAt(selectedIndices[i]);
48471 this.store.remove(rec);
48476 * Double click fires the event, but also, if this is draggable, and there is only one other
48477 * related DropZone, it transfers the selected node.
48479 onDblClick : function(e){
48480 var item = this.findItemFromChild(e.getTarget());
48482 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
48485 if (this.dragGroup) {
48486 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
48487 while (targets.indexOf(this.dropZone) > -1) {
48488 targets.remove(this.dropZone);
48490 if (targets.length == 1) {
48491 this.dragZone.cachedTarget = null;
48492 var el = Roo.get(targets[0].getEl());
48493 var box = el.getBox(true);
48494 targets[0].onNodeDrop(el.dom, {
48496 xy: [box.x, box.y + box.height - 1]
48497 }, null, this.getDragData(e));
48503 handleSelection: function(e) {
48504 this.dragZone.cachedTarget = null;
48505 var item = this.findItemFromChild(e.getTarget());
48507 this.clearSelections(true);
48510 if (item && (this.multiSelect || this.singleSelect)){
48511 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
48512 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
48513 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
48514 this.unselect(item);
48516 this.select(item, this.multiSelect && e.ctrlKey);
48517 this.lastSelection = item;
48522 onItemClick : function(item, index, e){
48523 if(this.fireEvent("beforeclick", this, index, item, e) === false){
48529 unselect : function(nodeInfo, suppressEvent){
48530 var node = this.getNode(nodeInfo);
48531 if(node && this.isSelected(node)){
48532 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
48533 Roo.fly(node).removeClass(this.selectedClass);
48534 this.selections.remove(node);
48535 if(!suppressEvent){
48536 this.fireEvent("selectionchange", this, this.selections);
48544 * Ext JS Library 1.1.1
48545 * Copyright(c) 2006-2007, Ext JS, LLC.
48547 * Originally Released Under LGPL - original licence link has changed is not relivant.
48550 * <script type="text/javascript">
48554 * @class Roo.LayoutManager
48555 * @extends Roo.util.Observable
48556 * Base class for layout managers.
48558 Roo.LayoutManager = function(container, config){
48559 Roo.LayoutManager.superclass.constructor.call(this);
48560 this.el = Roo.get(container);
48561 // ie scrollbar fix
48562 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
48563 document.body.scroll = "no";
48564 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
48565 this.el.position('relative');
48567 this.id = this.el.id;
48568 this.el.addClass("x-layout-container");
48569 /** false to disable window resize monitoring @type Boolean */
48570 this.monitorWindowResize = true;
48575 * Fires when a layout is performed.
48576 * @param {Roo.LayoutManager} this
48580 * @event regionresized
48581 * Fires when the user resizes a region.
48582 * @param {Roo.LayoutRegion} region The resized region
48583 * @param {Number} newSize The new size (width for east/west, height for north/south)
48585 "regionresized" : true,
48587 * @event regioncollapsed
48588 * Fires when a region is collapsed.
48589 * @param {Roo.LayoutRegion} region The collapsed region
48591 "regioncollapsed" : true,
48593 * @event regionexpanded
48594 * Fires when a region is expanded.
48595 * @param {Roo.LayoutRegion} region The expanded region
48597 "regionexpanded" : true
48599 this.updating = false;
48600 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48603 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
48605 * Returns true if this layout is currently being updated
48606 * @return {Boolean}
48608 isUpdating : function(){
48609 return this.updating;
48613 * Suspend the LayoutManager from doing auto-layouts while
48614 * making multiple add or remove calls
48616 beginUpdate : function(){
48617 this.updating = true;
48621 * Restore auto-layouts and optionally disable the manager from performing a layout
48622 * @param {Boolean} noLayout true to disable a layout update
48624 endUpdate : function(noLayout){
48625 this.updating = false;
48631 layout: function(){
48635 onRegionResized : function(region, newSize){
48636 this.fireEvent("regionresized", region, newSize);
48640 onRegionCollapsed : function(region){
48641 this.fireEvent("regioncollapsed", region);
48644 onRegionExpanded : function(region){
48645 this.fireEvent("regionexpanded", region);
48649 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
48650 * performs box-model adjustments.
48651 * @return {Object} The size as an object {width: (the width), height: (the height)}
48653 getViewSize : function(){
48655 if(this.el.dom != document.body){
48656 size = this.el.getSize();
48658 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
48660 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
48661 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
48666 * Returns the Element this layout is bound to.
48667 * @return {Roo.Element}
48669 getEl : function(){
48674 * Returns the specified region.
48675 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
48676 * @return {Roo.LayoutRegion}
48678 getRegion : function(target){
48679 return this.regions[target.toLowerCase()];
48682 onWindowResize : function(){
48683 if(this.monitorWindowResize){
48689 * Ext JS Library 1.1.1
48690 * Copyright(c) 2006-2007, Ext JS, LLC.
48692 * Originally Released Under LGPL - original licence link has changed is not relivant.
48695 * <script type="text/javascript">
48698 * @class Roo.BorderLayout
48699 * @extends Roo.LayoutManager
48700 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
48701 * please see: <br><br>
48702 * <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>
48703 * <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>
48706 var layout = new Roo.BorderLayout(document.body, {
48740 preferredTabWidth: 150
48745 var CP = Roo.ContentPanel;
48747 layout.beginUpdate();
48748 layout.add("north", new CP("north", "North"));
48749 layout.add("south", new CP("south", {title: "South", closable: true}));
48750 layout.add("west", new CP("west", {title: "West"}));
48751 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
48752 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
48753 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
48754 layout.getRegion("center").showPanel("center1");
48755 layout.endUpdate();
48758 <b>The container the layout is rendered into can be either the body element or any other element.
48759 If it is not the body element, the container needs to either be an absolute positioned element,
48760 or you will need to add "position:relative" to the css of the container. You will also need to specify
48761 the container size if it is not the body element.</b>
48764 * Create a new BorderLayout
48765 * @param {String/HTMLElement/Element} container The container this layout is bound to
48766 * @param {Object} config Configuration options
48768 Roo.BorderLayout = function(container, config){
48769 config = config || {};
48770 Roo.BorderLayout.superclass.constructor.call(this, container, config);
48771 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
48772 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
48773 var target = this.factory.validRegions[i];
48774 if(config[target]){
48775 this.addRegion(target, config[target]);
48780 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
48782 * Creates and adds a new region if it doesn't already exist.
48783 * @param {String} target The target region key (north, south, east, west or center).
48784 * @param {Object} config The regions config object
48785 * @return {BorderLayoutRegion} The new region
48787 addRegion : function(target, config){
48788 if(!this.regions[target]){
48789 var r = this.factory.create(target, this, config);
48790 this.bindRegion(target, r);
48792 return this.regions[target];
48796 bindRegion : function(name, r){
48797 this.regions[name] = r;
48798 r.on("visibilitychange", this.layout, this);
48799 r.on("paneladded", this.layout, this);
48800 r.on("panelremoved", this.layout, this);
48801 r.on("invalidated", this.layout, this);
48802 r.on("resized", this.onRegionResized, this);
48803 r.on("collapsed", this.onRegionCollapsed, this);
48804 r.on("expanded", this.onRegionExpanded, this);
48808 * Performs a layout update.
48810 layout : function(){
48811 if(this.updating) return;
48812 var size = this.getViewSize();
48813 var w = size.width;
48814 var h = size.height;
48819 //var x = 0, y = 0;
48821 var rs = this.regions;
48822 var north = rs["north"];
48823 var south = rs["south"];
48824 var west = rs["west"];
48825 var east = rs["east"];
48826 var center = rs["center"];
48827 //if(this.hideOnLayout){ // not supported anymore
48828 //c.el.setStyle("display", "none");
48830 if(north && north.isVisible()){
48831 var b = north.getBox();
48832 var m = north.getMargins();
48833 b.width = w - (m.left+m.right);
48836 centerY = b.height + b.y + m.bottom;
48837 centerH -= centerY;
48838 north.updateBox(this.safeBox(b));
48840 if(south && south.isVisible()){
48841 var b = south.getBox();
48842 var m = south.getMargins();
48843 b.width = w - (m.left+m.right);
48845 var totalHeight = (b.height + m.top + m.bottom);
48846 b.y = h - totalHeight + m.top;
48847 centerH -= totalHeight;
48848 south.updateBox(this.safeBox(b));
48850 if(west && west.isVisible()){
48851 var b = west.getBox();
48852 var m = west.getMargins();
48853 b.height = centerH - (m.top+m.bottom);
48855 b.y = centerY + m.top;
48856 var totalWidth = (b.width + m.left + m.right);
48857 centerX += totalWidth;
48858 centerW -= totalWidth;
48859 west.updateBox(this.safeBox(b));
48861 if(east && east.isVisible()){
48862 var b = east.getBox();
48863 var m = east.getMargins();
48864 b.height = centerH - (m.top+m.bottom);
48865 var totalWidth = (b.width + m.left + m.right);
48866 b.x = w - totalWidth + m.left;
48867 b.y = centerY + m.top;
48868 centerW -= totalWidth;
48869 east.updateBox(this.safeBox(b));
48872 var m = center.getMargins();
48874 x: centerX + m.left,
48875 y: centerY + m.top,
48876 width: centerW - (m.left+m.right),
48877 height: centerH - (m.top+m.bottom)
48879 //if(this.hideOnLayout){
48880 //center.el.setStyle("display", "block");
48882 center.updateBox(this.safeBox(centerBox));
48885 this.fireEvent("layout", this);
48889 safeBox : function(box){
48890 box.width = Math.max(0, box.width);
48891 box.height = Math.max(0, box.height);
48896 * Adds a ContentPanel (or subclass) to this layout.
48897 * @param {String} target The target region key (north, south, east, west or center).
48898 * @param {Roo.ContentPanel} panel The panel to add
48899 * @return {Roo.ContentPanel} The added panel
48901 add : function(target, panel){
48903 target = target.toLowerCase();
48904 return this.regions[target].add(panel);
48908 * Remove a ContentPanel (or subclass) to this layout.
48909 * @param {String} target The target region key (north, south, east, west or center).
48910 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
48911 * @return {Roo.ContentPanel} The removed panel
48913 remove : function(target, panel){
48914 target = target.toLowerCase();
48915 return this.regions[target].remove(panel);
48919 * Searches all regions for a panel with the specified id
48920 * @param {String} panelId
48921 * @return {Roo.ContentPanel} The panel or null if it wasn't found
48923 findPanel : function(panelId){
48924 var rs = this.regions;
48925 for(var target in rs){
48926 if(typeof rs[target] != "function"){
48927 var p = rs[target].getPanel(panelId);
48937 * Searches all regions for a panel with the specified id and activates (shows) it.
48938 * @param {String/ContentPanel} panelId The panels id or the panel itself
48939 * @return {Roo.ContentPanel} The shown panel or null
48941 showPanel : function(panelId) {
48942 var rs = this.regions;
48943 for(var target in rs){
48944 var r = rs[target];
48945 if(typeof r != "function"){
48946 if(r.hasPanel(panelId)){
48947 return r.showPanel(panelId);
48955 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
48956 * @param {Roo.state.Provider} provider (optional) An alternate state provider
48958 restoreState : function(provider){
48960 provider = Roo.state.Manager;
48962 var sm = new Roo.LayoutStateManager();
48963 sm.init(this, provider);
48967 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
48968 * object should contain properties for each region to add ContentPanels to, and each property's value should be
48969 * a valid ContentPanel config object. Example:
48971 // Create the main layout
48972 var layout = new Roo.BorderLayout('main-ct', {
48983 // Create and add multiple ContentPanels at once via configs
48986 id: 'source-files',
48988 title:'Ext Source Files',
49001 * @param {Object} regions An object containing ContentPanel configs by region name
49003 batchAdd : function(regions){
49004 this.beginUpdate();
49005 for(var rname in regions){
49006 var lr = this.regions[rname];
49008 this.addTypedPanels(lr, regions[rname]);
49015 addTypedPanels : function(lr, ps){
49016 if(typeof ps == 'string'){
49017 lr.add(new Roo.ContentPanel(ps));
49019 else if(ps instanceof Array){
49020 for(var i =0, len = ps.length; i < len; i++){
49021 this.addTypedPanels(lr, ps[i]);
49024 else if(!ps.events){ // raw config?
49026 delete ps.el; // prevent conflict
49027 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49029 else { // panel object assumed!
49034 * Adds a xtype elements to the layout.
49038 xtype : 'ContentPanel',
49045 xtype : 'NestedLayoutPanel',
49051 items : [ ... list of content panels or nested layout panels.. ]
49055 * @param {Object} cfg Xtype definition of item to add.
49057 addxtype : function(cfg)
49059 // basically accepts a pannel...
49060 // can accept a layout region..!?!?
49061 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49063 if (!cfg.xtype.match(/Panel$/)) {
49068 if (typeof(cfg.region) == 'undefined') {
49069 Roo.log("Failed to add Panel, region was not set");
49073 var region = cfg.region;
49079 xitems = cfg.items;
49086 case 'ContentPanel': // ContentPanel (el, cfg)
49087 case 'ScrollPanel': // ContentPanel (el, cfg)
49089 if(cfg.autoCreate) {
49090 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49092 var el = this.el.createChild();
49093 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49096 this.add(region, ret);
49100 case 'TreePanel': // our new panel!
49101 cfg.el = this.el.createChild();
49102 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49103 this.add(region, ret);
49106 case 'NestedLayoutPanel':
49107 // create a new Layout (which is a Border Layout...
49108 var el = this.el.createChild();
49109 var clayout = cfg.layout;
49111 clayout.items = clayout.items || [];
49112 // replace this exitems with the clayout ones..
49113 xitems = clayout.items;
49116 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49117 cfg.background = false;
49119 var layout = new Roo.BorderLayout(el, clayout);
49121 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49122 //console.log('adding nested layout panel ' + cfg.toSource());
49123 this.add(region, ret);
49124 nb = {}; /// find first...
49129 // needs grid and region
49131 //var el = this.getRegion(region).el.createChild();
49132 var el = this.el.createChild();
49133 // create the grid first...
49135 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49137 if (region == 'center' && this.active ) {
49138 cfg.background = false;
49140 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49142 this.add(region, ret);
49143 if (cfg.background) {
49144 ret.on('activate', function(gp) {
49145 if (!gp.grid.rendered) {
49160 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49162 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49163 this.add(region, ret);
49166 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49170 // GridPanel (grid, cfg)
49173 this.beginUpdate();
49177 Roo.each(xitems, function(i) {
49178 region = nb && i.region ? i.region : false;
49180 var add = ret.addxtype(i);
49183 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49184 if (!i.background) {
49185 abn[region] = nb[region] ;
49192 // make the last non-background panel active..
49193 //if (nb) { Roo.log(abn); }
49196 for(var r in abn) {
49197 region = this.getRegion(r);
49199 // tried using nb[r], but it does not work..
49201 region.showPanel(abn[r]);
49212 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49213 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49214 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49215 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49218 var CP = Roo.ContentPanel;
49220 var layout = Roo.BorderLayout.create({
49224 panels: [new CP("north", "North")]
49233 panels: [new CP("west", {title: "West"})]
49242 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49251 panels: [new CP("south", {title: "South", closable: true})]
49258 preferredTabWidth: 150,
49260 new CP("center1", {title: "Close Me", closable: true}),
49261 new CP("center2", {title: "Center Panel", closable: false})
49266 layout.getRegion("center").showPanel("center1");
49271 Roo.BorderLayout.create = function(config, targetEl){
49272 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49273 layout.beginUpdate();
49274 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49275 for(var j = 0, jlen = regions.length; j < jlen; j++){
49276 var lr = regions[j];
49277 if(layout.regions[lr] && config[lr].panels){
49278 var r = layout.regions[lr];
49279 var ps = config[lr].panels;
49280 layout.addTypedPanels(r, ps);
49283 layout.endUpdate();
49288 Roo.BorderLayout.RegionFactory = {
49290 validRegions : ["north","south","east","west","center"],
49293 create : function(target, mgr, config){
49294 target = target.toLowerCase();
49295 if(config.lightweight || config.basic){
49296 return new Roo.BasicLayoutRegion(mgr, config, target);
49300 return new Roo.NorthLayoutRegion(mgr, config);
49302 return new Roo.SouthLayoutRegion(mgr, config);
49304 return new Roo.EastLayoutRegion(mgr, config);
49306 return new Roo.WestLayoutRegion(mgr, config);
49308 return new Roo.CenterLayoutRegion(mgr, config);
49310 throw 'Layout region "'+target+'" not supported.';
49314 * Ext JS Library 1.1.1
49315 * Copyright(c) 2006-2007, Ext JS, LLC.
49317 * Originally Released Under LGPL - original licence link has changed is not relivant.
49320 * <script type="text/javascript">
49324 * @class Roo.BasicLayoutRegion
49325 * @extends Roo.util.Observable
49326 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49327 * and does not have a titlebar, tabs or any other features. All it does is size and position
49328 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49330 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49332 this.position = pos;
49335 * @scope Roo.BasicLayoutRegion
49339 * @event beforeremove
49340 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49341 * @param {Roo.LayoutRegion} this
49342 * @param {Roo.ContentPanel} panel The panel
49343 * @param {Object} e The cancel event object
49345 "beforeremove" : true,
49347 * @event invalidated
49348 * Fires when the layout for this region is changed.
49349 * @param {Roo.LayoutRegion} this
49351 "invalidated" : true,
49353 * @event visibilitychange
49354 * Fires when this region is shown or hidden
49355 * @param {Roo.LayoutRegion} this
49356 * @param {Boolean} visibility true or false
49358 "visibilitychange" : true,
49360 * @event paneladded
49361 * Fires when a panel is added.
49362 * @param {Roo.LayoutRegion} this
49363 * @param {Roo.ContentPanel} panel The panel
49365 "paneladded" : true,
49367 * @event panelremoved
49368 * Fires when a panel is removed.
49369 * @param {Roo.LayoutRegion} this
49370 * @param {Roo.ContentPanel} panel The panel
49372 "panelremoved" : true,
49375 * Fires when this region is collapsed.
49376 * @param {Roo.LayoutRegion} this
49378 "collapsed" : true,
49381 * Fires when this region is expanded.
49382 * @param {Roo.LayoutRegion} this
49387 * Fires when this region is slid into view.
49388 * @param {Roo.LayoutRegion} this
49390 "slideshow" : true,
49393 * Fires when this region slides out of view.
49394 * @param {Roo.LayoutRegion} this
49396 "slidehide" : true,
49398 * @event panelactivated
49399 * Fires when a panel is activated.
49400 * @param {Roo.LayoutRegion} this
49401 * @param {Roo.ContentPanel} panel The activated panel
49403 "panelactivated" : true,
49406 * Fires when the user resizes this region.
49407 * @param {Roo.LayoutRegion} this
49408 * @param {Number} newSize The new size (width for east/west, height for north/south)
49412 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49413 this.panels = new Roo.util.MixedCollection();
49414 this.panels.getKey = this.getPanelId.createDelegate(this);
49416 this.activePanel = null;
49417 // ensure listeners are added...
49419 if (config.listeners || config.events) {
49420 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49421 listeners : config.listeners || {},
49422 events : config.events || {}
49426 if(skipConfig !== true){
49427 this.applyConfig(config);
49431 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49432 getPanelId : function(p){
49436 applyConfig : function(config){
49437 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49438 this.config = config;
49443 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49444 * the width, for horizontal (north, south) the height.
49445 * @param {Number} newSize The new width or height
49447 resizeTo : function(newSize){
49448 var el = this.el ? this.el :
49449 (this.activePanel ? this.activePanel.getEl() : null);
49451 switch(this.position){
49454 el.setWidth(newSize);
49455 this.fireEvent("resized", this, newSize);
49459 el.setHeight(newSize);
49460 this.fireEvent("resized", this, newSize);
49466 getBox : function(){
49467 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
49470 getMargins : function(){
49471 return this.margins;
49474 updateBox : function(box){
49476 var el = this.activePanel.getEl();
49477 el.dom.style.left = box.x + "px";
49478 el.dom.style.top = box.y + "px";
49479 this.activePanel.setSize(box.width, box.height);
49483 * Returns the container element for this region.
49484 * @return {Roo.Element}
49486 getEl : function(){
49487 return this.activePanel;
49491 * Returns true if this region is currently visible.
49492 * @return {Boolean}
49494 isVisible : function(){
49495 return this.activePanel ? true : false;
49498 setActivePanel : function(panel){
49499 panel = this.getPanel(panel);
49500 if(this.activePanel && this.activePanel != panel){
49501 this.activePanel.setActiveState(false);
49502 this.activePanel.getEl().setLeftTop(-10000,-10000);
49504 this.activePanel = panel;
49505 panel.setActiveState(true);
49507 panel.setSize(this.box.width, this.box.height);
49509 this.fireEvent("panelactivated", this, panel);
49510 this.fireEvent("invalidated");
49514 * Show the specified panel.
49515 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
49516 * @return {Roo.ContentPanel} The shown panel or null
49518 showPanel : function(panel){
49519 if(panel = this.getPanel(panel)){
49520 this.setActivePanel(panel);
49526 * Get the active panel for this region.
49527 * @return {Roo.ContentPanel} The active panel or null
49529 getActivePanel : function(){
49530 return this.activePanel;
49534 * Add the passed ContentPanel(s)
49535 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49536 * @return {Roo.ContentPanel} The panel added (if only one was added)
49538 add : function(panel){
49539 if(arguments.length > 1){
49540 for(var i = 0, len = arguments.length; i < len; i++) {
49541 this.add(arguments[i]);
49545 if(this.hasPanel(panel)){
49546 this.showPanel(panel);
49549 var el = panel.getEl();
49550 if(el.dom.parentNode != this.mgr.el.dom){
49551 this.mgr.el.dom.appendChild(el.dom);
49553 if(panel.setRegion){
49554 panel.setRegion(this);
49556 this.panels.add(panel);
49557 el.setStyle("position", "absolute");
49558 if(!panel.background){
49559 this.setActivePanel(panel);
49560 if(this.config.initialSize && this.panels.getCount()==1){
49561 this.resizeTo(this.config.initialSize);
49564 this.fireEvent("paneladded", this, panel);
49569 * Returns true if the panel is in this region.
49570 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49571 * @return {Boolean}
49573 hasPanel : function(panel){
49574 if(typeof panel == "object"){ // must be panel obj
49575 panel = panel.getId();
49577 return this.getPanel(panel) ? true : false;
49581 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49582 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49583 * @param {Boolean} preservePanel Overrides the config preservePanel option
49584 * @return {Roo.ContentPanel} The panel that was removed
49586 remove : function(panel, preservePanel){
49587 panel = this.getPanel(panel);
49592 this.fireEvent("beforeremove", this, panel, e);
49593 if(e.cancel === true){
49596 var panelId = panel.getId();
49597 this.panels.removeKey(panelId);
49602 * Returns the panel specified or null if it's not in this region.
49603 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49604 * @return {Roo.ContentPanel}
49606 getPanel : function(id){
49607 if(typeof id == "object"){ // must be panel obj
49610 return this.panels.get(id);
49614 * Returns this regions position (north/south/east/west/center).
49617 getPosition: function(){
49618 return this.position;
49622 * Ext JS Library 1.1.1
49623 * Copyright(c) 2006-2007, Ext JS, LLC.
49625 * Originally Released Under LGPL - original licence link has changed is not relivant.
49628 * <script type="text/javascript">
49632 * @class Roo.LayoutRegion
49633 * @extends Roo.BasicLayoutRegion
49634 * This class represents a region in a layout manager.
49635 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
49636 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
49637 * @cfg {Boolean} floatable False to disable floating (defaults to true)
49638 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
49639 * @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})
49640 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
49641 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
49642 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
49643 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
49644 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
49645 * @cfg {String} title The title for the region (overrides panel titles)
49646 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
49647 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
49648 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
49649 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
49650 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
49651 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
49652 * the space available, similar to FireFox 1.5 tabs (defaults to false)
49653 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
49654 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
49655 * @cfg {Boolean} showPin True to show a pin button
49656 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
49657 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
49658 * @cfg {Boolean} disableTabTips True to disable tab tooltips
49659 * @cfg {Number} width For East/West panels
49660 * @cfg {Number} height For North/South panels
49661 * @cfg {Boolean} split To show the splitter
49662 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
49664 Roo.LayoutRegion = function(mgr, config, pos){
49665 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
49666 var dh = Roo.DomHelper;
49667 /** This region's container element
49668 * @type Roo.Element */
49669 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
49670 /** This region's title element
49671 * @type Roo.Element */
49673 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
49674 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
49675 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
49677 this.titleEl.enableDisplayMode();
49678 /** This region's title text element
49679 * @type HTMLElement */
49680 this.titleTextEl = this.titleEl.dom.firstChild;
49681 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
49682 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
49683 this.closeBtn.enableDisplayMode();
49684 this.closeBtn.on("click", this.closeClicked, this);
49685 this.closeBtn.hide();
49687 this.createBody(config);
49688 this.visible = true;
49689 this.collapsed = false;
49691 if(config.hideWhenEmpty){
49693 this.on("paneladded", this.validateVisibility, this);
49694 this.on("panelremoved", this.validateVisibility, this);
49696 this.applyConfig(config);
49699 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
49701 createBody : function(){
49702 /** This region's body element
49703 * @type Roo.Element */
49704 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
49707 applyConfig : function(c){
49708 if(c.collapsible && this.position != "center" && !this.collapsedEl){
49709 var dh = Roo.DomHelper;
49710 if(c.titlebar !== false){
49711 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
49712 this.collapseBtn.on("click", this.collapse, this);
49713 this.collapseBtn.enableDisplayMode();
49715 if(c.showPin === true || this.showPin){
49716 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
49717 this.stickBtn.enableDisplayMode();
49718 this.stickBtn.on("click", this.expand, this);
49719 this.stickBtn.hide();
49722 /** This region's collapsed element
49723 * @type Roo.Element */
49724 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
49725 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
49727 if(c.floatable !== false){
49728 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
49729 this.collapsedEl.on("click", this.collapseClick, this);
49732 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
49733 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
49734 id: "message", unselectable: "on", style:{"float":"left"}});
49735 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
49737 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
49738 this.expandBtn.on("click", this.expand, this);
49740 if(this.collapseBtn){
49741 this.collapseBtn.setVisible(c.collapsible == true);
49743 this.cmargins = c.cmargins || this.cmargins ||
49744 (this.position == "west" || this.position == "east" ?
49745 {top: 0, left: 2, right:2, bottom: 0} :
49746 {top: 2, left: 0, right:0, bottom: 2});
49747 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49748 this.bottomTabs = c.tabPosition != "top";
49749 this.autoScroll = c.autoScroll || false;
49750 if(this.autoScroll){
49751 this.bodyEl.setStyle("overflow", "auto");
49753 this.bodyEl.setStyle("overflow", "hidden");
49755 //if(c.titlebar !== false){
49756 if((!c.titlebar && !c.title) || c.titlebar === false){
49757 this.titleEl.hide();
49759 this.titleEl.show();
49761 this.titleTextEl.innerHTML = c.title;
49765 this.duration = c.duration || .30;
49766 this.slideDuration = c.slideDuration || .45;
49769 this.collapse(true);
49776 * Returns true if this region is currently visible.
49777 * @return {Boolean}
49779 isVisible : function(){
49780 return this.visible;
49784 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
49785 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
49787 setCollapsedTitle : function(title){
49788 title = title || " ";
49789 if(this.collapsedTitleTextEl){
49790 this.collapsedTitleTextEl.innerHTML = title;
49794 getBox : function(){
49796 if(!this.collapsed){
49797 b = this.el.getBox(false, true);
49799 b = this.collapsedEl.getBox(false, true);
49804 getMargins : function(){
49805 return this.collapsed ? this.cmargins : this.margins;
49808 highlight : function(){
49809 this.el.addClass("x-layout-panel-dragover");
49812 unhighlight : function(){
49813 this.el.removeClass("x-layout-panel-dragover");
49816 updateBox : function(box){
49818 if(!this.collapsed){
49819 this.el.dom.style.left = box.x + "px";
49820 this.el.dom.style.top = box.y + "px";
49821 this.updateBody(box.width, box.height);
49823 this.collapsedEl.dom.style.left = box.x + "px";
49824 this.collapsedEl.dom.style.top = box.y + "px";
49825 this.collapsedEl.setSize(box.width, box.height);
49828 this.tabs.autoSizeTabs();
49832 updateBody : function(w, h){
49834 this.el.setWidth(w);
49835 w -= this.el.getBorderWidth("rl");
49836 if(this.config.adjustments){
49837 w += this.config.adjustments[0];
49841 this.el.setHeight(h);
49842 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
49843 h -= this.el.getBorderWidth("tb");
49844 if(this.config.adjustments){
49845 h += this.config.adjustments[1];
49847 this.bodyEl.setHeight(h);
49849 h = this.tabs.syncHeight(h);
49852 if(this.panelSize){
49853 w = w !== null ? w : this.panelSize.width;
49854 h = h !== null ? h : this.panelSize.height;
49856 if(this.activePanel){
49857 var el = this.activePanel.getEl();
49858 w = w !== null ? w : el.getWidth();
49859 h = h !== null ? h : el.getHeight();
49860 this.panelSize = {width: w, height: h};
49861 this.activePanel.setSize(w, h);
49863 if(Roo.isIE && this.tabs){
49864 this.tabs.el.repaint();
49869 * Returns the container element for this region.
49870 * @return {Roo.Element}
49872 getEl : function(){
49877 * Hides this region.
49880 if(!this.collapsed){
49881 this.el.dom.style.left = "-2000px";
49884 this.collapsedEl.dom.style.left = "-2000px";
49885 this.collapsedEl.hide();
49887 this.visible = false;
49888 this.fireEvent("visibilitychange", this, false);
49892 * Shows this region if it was previously hidden.
49895 if(!this.collapsed){
49898 this.collapsedEl.show();
49900 this.visible = true;
49901 this.fireEvent("visibilitychange", this, true);
49904 closeClicked : function(){
49905 if(this.activePanel){
49906 this.remove(this.activePanel);
49910 collapseClick : function(e){
49912 e.stopPropagation();
49915 e.stopPropagation();
49921 * Collapses this region.
49922 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
49924 collapse : function(skipAnim){
49925 if(this.collapsed) return;
49926 this.collapsed = true;
49928 this.split.el.hide();
49930 if(this.config.animate && skipAnim !== true){
49931 this.fireEvent("invalidated", this);
49932 this.animateCollapse();
49934 this.el.setLocation(-20000,-20000);
49936 this.collapsedEl.show();
49937 this.fireEvent("collapsed", this);
49938 this.fireEvent("invalidated", this);
49942 animateCollapse : function(){
49947 * Expands this region if it was previously collapsed.
49948 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
49949 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
49951 expand : function(e, skipAnim){
49952 if(e) e.stopPropagation();
49953 if(!this.collapsed || this.el.hasActiveFx()) return;
49955 this.afterSlideIn();
49958 this.collapsed = false;
49959 if(this.config.animate && skipAnim !== true){
49960 this.animateExpand();
49964 this.split.el.show();
49966 this.collapsedEl.setLocation(-2000,-2000);
49967 this.collapsedEl.hide();
49968 this.fireEvent("invalidated", this);
49969 this.fireEvent("expanded", this);
49973 animateExpand : function(){
49977 initTabs : function()
49979 this.bodyEl.setStyle("overflow", "hidden");
49980 var ts = new Roo.TabPanel(
49983 tabPosition: this.bottomTabs ? 'bottom' : 'top',
49984 disableTooltips: this.config.disableTabTips,
49985 toolbar : this.config.toolbar
49988 if(this.config.hideTabs){
49989 ts.stripWrap.setDisplayed(false);
49992 ts.resizeTabs = this.config.resizeTabs === true;
49993 ts.minTabWidth = this.config.minTabWidth || 40;
49994 ts.maxTabWidth = this.config.maxTabWidth || 250;
49995 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
49996 ts.monitorResize = false;
49997 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49998 ts.bodyEl.addClass('x-layout-tabs-body');
49999 this.panels.each(this.initPanelAsTab, this);
50002 initPanelAsTab : function(panel){
50003 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50004 this.config.closeOnTab && panel.isClosable());
50005 if(panel.tabTip !== undefined){
50006 ti.setTooltip(panel.tabTip);
50008 ti.on("activate", function(){
50009 this.setActivePanel(panel);
50011 if(this.config.closeOnTab){
50012 ti.on("beforeclose", function(t, e){
50014 this.remove(panel);
50020 updatePanelTitle : function(panel, title){
50021 if(this.activePanel == panel){
50022 this.updateTitle(title);
50025 var ti = this.tabs.getTab(panel.getEl().id);
50027 if(panel.tabTip !== undefined){
50028 ti.setTooltip(panel.tabTip);
50033 updateTitle : function(title){
50034 if(this.titleTextEl && !this.config.title){
50035 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50039 setActivePanel : function(panel){
50040 panel = this.getPanel(panel);
50041 if(this.activePanel && this.activePanel != panel){
50042 this.activePanel.setActiveState(false);
50044 this.activePanel = panel;
50045 panel.setActiveState(true);
50046 if(this.panelSize){
50047 panel.setSize(this.panelSize.width, this.panelSize.height);
50050 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50052 this.updateTitle(panel.getTitle());
50054 this.fireEvent("invalidated", this);
50056 this.fireEvent("panelactivated", this, panel);
50060 * Shows the specified panel.
50061 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50062 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50064 showPanel : function(panel){
50065 if(panel = this.getPanel(panel)){
50067 var tab = this.tabs.getTab(panel.getEl().id);
50068 if(tab.isHidden()){
50069 this.tabs.unhideTab(tab.id);
50073 this.setActivePanel(panel);
50080 * Get the active panel for this region.
50081 * @return {Roo.ContentPanel} The active panel or null
50083 getActivePanel : function(){
50084 return this.activePanel;
50087 validateVisibility : function(){
50088 if(this.panels.getCount() < 1){
50089 this.updateTitle(" ");
50090 this.closeBtn.hide();
50093 if(!this.isVisible()){
50100 * Adds the passed ContentPanel(s) to this region.
50101 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50102 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50104 add : function(panel){
50105 if(arguments.length > 1){
50106 for(var i = 0, len = arguments.length; i < len; i++) {
50107 this.add(arguments[i]);
50111 if(this.hasPanel(panel)){
50112 this.showPanel(panel);
50115 panel.setRegion(this);
50116 this.panels.add(panel);
50117 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50118 this.bodyEl.dom.appendChild(panel.getEl().dom);
50119 if(panel.background !== true){
50120 this.setActivePanel(panel);
50122 this.fireEvent("paneladded", this, panel);
50128 this.initPanelAsTab(panel);
50130 if(panel.background !== true){
50131 this.tabs.activate(panel.getEl().id);
50133 this.fireEvent("paneladded", this, panel);
50138 * Hides the tab for the specified panel.
50139 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50141 hidePanel : function(panel){
50142 if(this.tabs && (panel = this.getPanel(panel))){
50143 this.tabs.hideTab(panel.getEl().id);
50148 * Unhides the tab for a previously hidden panel.
50149 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50151 unhidePanel : function(panel){
50152 if(this.tabs && (panel = this.getPanel(panel))){
50153 this.tabs.unhideTab(panel.getEl().id);
50157 clearPanels : function(){
50158 while(this.panels.getCount() > 0){
50159 this.remove(this.panels.first());
50164 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50165 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50166 * @param {Boolean} preservePanel Overrides the config preservePanel option
50167 * @return {Roo.ContentPanel} The panel that was removed
50169 remove : function(panel, preservePanel){
50170 panel = this.getPanel(panel);
50175 this.fireEvent("beforeremove", this, panel, e);
50176 if(e.cancel === true){
50179 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50180 var panelId = panel.getId();
50181 this.panels.removeKey(panelId);
50183 document.body.appendChild(panel.getEl().dom);
50186 this.tabs.removeTab(panel.getEl().id);
50187 }else if (!preservePanel){
50188 this.bodyEl.dom.removeChild(panel.getEl().dom);
50190 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50191 var p = this.panels.first();
50192 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50193 tempEl.appendChild(p.getEl().dom);
50194 this.bodyEl.update("");
50195 this.bodyEl.dom.appendChild(p.getEl().dom);
50197 this.updateTitle(p.getTitle());
50199 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50200 this.setActivePanel(p);
50202 panel.setRegion(null);
50203 if(this.activePanel == panel){
50204 this.activePanel = null;
50206 if(this.config.autoDestroy !== false && preservePanel !== true){
50207 try{panel.destroy();}catch(e){}
50209 this.fireEvent("panelremoved", this, panel);
50214 * Returns the TabPanel component used by this region
50215 * @return {Roo.TabPanel}
50217 getTabs : function(){
50221 createTool : function(parentEl, className){
50222 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50223 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50224 btn.addClassOnOver("x-layout-tools-button-over");
50229 * Ext JS Library 1.1.1
50230 * Copyright(c) 2006-2007, Ext JS, LLC.
50232 * Originally Released Under LGPL - original licence link has changed is not relivant.
50235 * <script type="text/javascript">
50241 * @class Roo.SplitLayoutRegion
50242 * @extends Roo.LayoutRegion
50243 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50245 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50246 this.cursor = cursor;
50247 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50250 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50251 splitTip : "Drag to resize.",
50252 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50253 useSplitTips : false,
50255 applyConfig : function(config){
50256 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50259 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50260 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50261 /** The SplitBar for this region
50262 * @type Roo.SplitBar */
50263 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50264 this.split.on("moved", this.onSplitMove, this);
50265 this.split.useShim = config.useShim === true;
50266 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50267 if(this.useSplitTips){
50268 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50270 if(config.collapsible){
50271 this.split.el.on("dblclick", this.collapse, this);
50274 if(typeof config.minSize != "undefined"){
50275 this.split.minSize = config.minSize;
50277 if(typeof config.maxSize != "undefined"){
50278 this.split.maxSize = config.maxSize;
50280 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50281 this.hideSplitter();
50286 getHMaxSize : function(){
50287 var cmax = this.config.maxSize || 10000;
50288 var center = this.mgr.getRegion("center");
50289 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50292 getVMaxSize : function(){
50293 var cmax = this.config.maxSize || 10000;
50294 var center = this.mgr.getRegion("center");
50295 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50298 onSplitMove : function(split, newSize){
50299 this.fireEvent("resized", this, newSize);
50303 * Returns the {@link Roo.SplitBar} for this region.
50304 * @return {Roo.SplitBar}
50306 getSplitBar : function(){
50311 this.hideSplitter();
50312 Roo.SplitLayoutRegion.superclass.hide.call(this);
50315 hideSplitter : function(){
50317 this.split.el.setLocation(-2000,-2000);
50318 this.split.el.hide();
50324 this.split.el.show();
50326 Roo.SplitLayoutRegion.superclass.show.call(this);
50329 beforeSlide: function(){
50330 if(Roo.isGecko){// firefox overflow auto bug workaround
50331 this.bodyEl.clip();
50332 if(this.tabs) this.tabs.bodyEl.clip();
50333 if(this.activePanel){
50334 this.activePanel.getEl().clip();
50336 if(this.activePanel.beforeSlide){
50337 this.activePanel.beforeSlide();
50343 afterSlide : function(){
50344 if(Roo.isGecko){// firefox overflow auto bug workaround
50345 this.bodyEl.unclip();
50346 if(this.tabs) this.tabs.bodyEl.unclip();
50347 if(this.activePanel){
50348 this.activePanel.getEl().unclip();
50349 if(this.activePanel.afterSlide){
50350 this.activePanel.afterSlide();
50356 initAutoHide : function(){
50357 if(this.autoHide !== false){
50358 if(!this.autoHideHd){
50359 var st = new Roo.util.DelayedTask(this.slideIn, this);
50360 this.autoHideHd = {
50361 "mouseout": function(e){
50362 if(!e.within(this.el, true)){
50366 "mouseover" : function(e){
50372 this.el.on(this.autoHideHd);
50376 clearAutoHide : function(){
50377 if(this.autoHide !== false){
50378 this.el.un("mouseout", this.autoHideHd.mouseout);
50379 this.el.un("mouseover", this.autoHideHd.mouseover);
50383 clearMonitor : function(){
50384 Roo.get(document).un("click", this.slideInIf, this);
50387 // these names are backwards but not changed for compat
50388 slideOut : function(){
50389 if(this.isSlid || this.el.hasActiveFx()){
50392 this.isSlid = true;
50393 if(this.collapseBtn){
50394 this.collapseBtn.hide();
50396 this.closeBtnState = this.closeBtn.getStyle('display');
50397 this.closeBtn.hide();
50399 this.stickBtn.show();
50402 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50403 this.beforeSlide();
50404 this.el.setStyle("z-index", 10001);
50405 this.el.slideIn(this.getSlideAnchor(), {
50406 callback: function(){
50408 this.initAutoHide();
50409 Roo.get(document).on("click", this.slideInIf, this);
50410 this.fireEvent("slideshow", this);
50417 afterSlideIn : function(){
50418 this.clearAutoHide();
50419 this.isSlid = false;
50420 this.clearMonitor();
50421 this.el.setStyle("z-index", "");
50422 if(this.collapseBtn){
50423 this.collapseBtn.show();
50425 this.closeBtn.setStyle('display', this.closeBtnState);
50427 this.stickBtn.hide();
50429 this.fireEvent("slidehide", this);
50432 slideIn : function(cb){
50433 if(!this.isSlid || this.el.hasActiveFx()){
50437 this.isSlid = false;
50438 this.beforeSlide();
50439 this.el.slideOut(this.getSlideAnchor(), {
50440 callback: function(){
50441 this.el.setLeftTop(-10000, -10000);
50443 this.afterSlideIn();
50451 slideInIf : function(e){
50452 if(!e.within(this.el)){
50457 animateCollapse : function(){
50458 this.beforeSlide();
50459 this.el.setStyle("z-index", 20000);
50460 var anchor = this.getSlideAnchor();
50461 this.el.slideOut(anchor, {
50462 callback : function(){
50463 this.el.setStyle("z-index", "");
50464 this.collapsedEl.slideIn(anchor, {duration:.3});
50466 this.el.setLocation(-10000,-10000);
50468 this.fireEvent("collapsed", this);
50475 animateExpand : function(){
50476 this.beforeSlide();
50477 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
50478 this.el.setStyle("z-index", 20000);
50479 this.collapsedEl.hide({
50482 this.el.slideIn(this.getSlideAnchor(), {
50483 callback : function(){
50484 this.el.setStyle("z-index", "");
50487 this.split.el.show();
50489 this.fireEvent("invalidated", this);
50490 this.fireEvent("expanded", this);
50518 getAnchor : function(){
50519 return this.anchors[this.position];
50522 getCollapseAnchor : function(){
50523 return this.canchors[this.position];
50526 getSlideAnchor : function(){
50527 return this.sanchors[this.position];
50530 getAlignAdj : function(){
50531 var cm = this.cmargins;
50532 switch(this.position){
50548 getExpandAdj : function(){
50549 var c = this.collapsedEl, cm = this.cmargins;
50550 switch(this.position){
50552 return [-(cm.right+c.getWidth()+cm.left), 0];
50555 return [cm.right+c.getWidth()+cm.left, 0];
50558 return [0, -(cm.top+cm.bottom+c.getHeight())];
50561 return [0, cm.top+cm.bottom+c.getHeight()];
50567 * Ext JS Library 1.1.1
50568 * Copyright(c) 2006-2007, Ext JS, LLC.
50570 * Originally Released Under LGPL - original licence link has changed is not relivant.
50573 * <script type="text/javascript">
50576 * These classes are private internal classes
50578 Roo.CenterLayoutRegion = function(mgr, config){
50579 Roo.LayoutRegion.call(this, mgr, config, "center");
50580 this.visible = true;
50581 this.minWidth = config.minWidth || 20;
50582 this.minHeight = config.minHeight || 20;
50585 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
50587 // center panel can't be hidden
50591 // center panel can't be hidden
50594 getMinWidth: function(){
50595 return this.minWidth;
50598 getMinHeight: function(){
50599 return this.minHeight;
50604 Roo.NorthLayoutRegion = function(mgr, config){
50605 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
50607 this.split.placement = Roo.SplitBar.TOP;
50608 this.split.orientation = Roo.SplitBar.VERTICAL;
50609 this.split.el.addClass("x-layout-split-v");
50611 var size = config.initialSize || config.height;
50612 if(typeof size != "undefined"){
50613 this.el.setHeight(size);
50616 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
50617 orientation: Roo.SplitBar.VERTICAL,
50618 getBox : function(){
50619 if(this.collapsed){
50620 return this.collapsedEl.getBox();
50622 var box = this.el.getBox();
50624 box.height += this.split.el.getHeight();
50629 updateBox : function(box){
50630 if(this.split && !this.collapsed){
50631 box.height -= this.split.el.getHeight();
50632 this.split.el.setLeft(box.x);
50633 this.split.el.setTop(box.y+box.height);
50634 this.split.el.setWidth(box.width);
50636 if(this.collapsed){
50637 this.updateBody(box.width, null);
50639 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50643 Roo.SouthLayoutRegion = function(mgr, config){
50644 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
50646 this.split.placement = Roo.SplitBar.BOTTOM;
50647 this.split.orientation = Roo.SplitBar.VERTICAL;
50648 this.split.el.addClass("x-layout-split-v");
50650 var size = config.initialSize || config.height;
50651 if(typeof size != "undefined"){
50652 this.el.setHeight(size);
50655 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
50656 orientation: Roo.SplitBar.VERTICAL,
50657 getBox : function(){
50658 if(this.collapsed){
50659 return this.collapsedEl.getBox();
50661 var box = this.el.getBox();
50663 var sh = this.split.el.getHeight();
50670 updateBox : function(box){
50671 if(this.split && !this.collapsed){
50672 var sh = this.split.el.getHeight();
50675 this.split.el.setLeft(box.x);
50676 this.split.el.setTop(box.y-sh);
50677 this.split.el.setWidth(box.width);
50679 if(this.collapsed){
50680 this.updateBody(box.width, null);
50682 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50686 Roo.EastLayoutRegion = function(mgr, config){
50687 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
50689 this.split.placement = Roo.SplitBar.RIGHT;
50690 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50691 this.split.el.addClass("x-layout-split-h");
50693 var size = config.initialSize || config.width;
50694 if(typeof size != "undefined"){
50695 this.el.setWidth(size);
50698 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
50699 orientation: Roo.SplitBar.HORIZONTAL,
50700 getBox : function(){
50701 if(this.collapsed){
50702 return this.collapsedEl.getBox();
50704 var box = this.el.getBox();
50706 var sw = this.split.el.getWidth();
50713 updateBox : function(box){
50714 if(this.split && !this.collapsed){
50715 var sw = this.split.el.getWidth();
50717 this.split.el.setLeft(box.x);
50718 this.split.el.setTop(box.y);
50719 this.split.el.setHeight(box.height);
50722 if(this.collapsed){
50723 this.updateBody(null, box.height);
50725 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50729 Roo.WestLayoutRegion = function(mgr, config){
50730 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
50732 this.split.placement = Roo.SplitBar.LEFT;
50733 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50734 this.split.el.addClass("x-layout-split-h");
50736 var size = config.initialSize || config.width;
50737 if(typeof size != "undefined"){
50738 this.el.setWidth(size);
50741 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
50742 orientation: Roo.SplitBar.HORIZONTAL,
50743 getBox : function(){
50744 if(this.collapsed){
50745 return this.collapsedEl.getBox();
50747 var box = this.el.getBox();
50749 box.width += this.split.el.getWidth();
50754 updateBox : function(box){
50755 if(this.split && !this.collapsed){
50756 var sw = this.split.el.getWidth();
50758 this.split.el.setLeft(box.x+box.width);
50759 this.split.el.setTop(box.y);
50760 this.split.el.setHeight(box.height);
50762 if(this.collapsed){
50763 this.updateBody(null, box.height);
50765 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50770 * Ext JS Library 1.1.1
50771 * Copyright(c) 2006-2007, Ext JS, LLC.
50773 * Originally Released Under LGPL - original licence link has changed is not relivant.
50776 * <script type="text/javascript">
50781 * Private internal class for reading and applying state
50783 Roo.LayoutStateManager = function(layout){
50784 // default empty state
50793 Roo.LayoutStateManager.prototype = {
50794 init : function(layout, provider){
50795 this.provider = provider;
50796 var state = provider.get(layout.id+"-layout-state");
50798 var wasUpdating = layout.isUpdating();
50800 layout.beginUpdate();
50802 for(var key in state){
50803 if(typeof state[key] != "function"){
50804 var rstate = state[key];
50805 var r = layout.getRegion(key);
50808 r.resizeTo(rstate.size);
50810 if(rstate.collapsed == true){
50813 r.expand(null, true);
50819 layout.endUpdate();
50821 this.state = state;
50823 this.layout = layout;
50824 layout.on("regionresized", this.onRegionResized, this);
50825 layout.on("regioncollapsed", this.onRegionCollapsed, this);
50826 layout.on("regionexpanded", this.onRegionExpanded, this);
50829 storeState : function(){
50830 this.provider.set(this.layout.id+"-layout-state", this.state);
50833 onRegionResized : function(region, newSize){
50834 this.state[region.getPosition()].size = newSize;
50838 onRegionCollapsed : function(region){
50839 this.state[region.getPosition()].collapsed = true;
50843 onRegionExpanded : function(region){
50844 this.state[region.getPosition()].collapsed = false;
50849 * Ext JS Library 1.1.1
50850 * Copyright(c) 2006-2007, Ext JS, LLC.
50852 * Originally Released Under LGPL - original licence link has changed is not relivant.
50855 * <script type="text/javascript">
50858 * @class Roo.ContentPanel
50859 * @extends Roo.util.Observable
50860 * A basic ContentPanel element.
50861 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
50862 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
50863 * @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
50864 * @cfg {Boolean} closable True if the panel can be closed/removed
50865 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
50866 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
50867 * @cfg {Toolbar} toolbar A toolbar for this panel
50868 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
50869 * @cfg {String} title The title for this panel
50870 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
50871 * @cfg {String} url Calls {@link #setUrl} with this value
50872 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
50873 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
50874 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
50875 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
50878 * Create a new ContentPanel.
50879 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
50880 * @param {String/Object} config A string to set only the title or a config object
50881 * @param {String} content (optional) Set the HTML content for this panel
50882 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
50884 Roo.ContentPanel = function(el, config, content){
50888 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
50892 if (config && config.parentLayout) {
50893 el = config.parentLayout.el.createChild();
50896 if(el.autoCreate){ // xtype is available if this is called from factory
50900 this.el = Roo.get(el);
50901 if(!this.el && config && config.autoCreate){
50902 if(typeof config.autoCreate == "object"){
50903 if(!config.autoCreate.id){
50904 config.autoCreate.id = config.id||el;
50906 this.el = Roo.DomHelper.append(document.body,
50907 config.autoCreate, true);
50909 this.el = Roo.DomHelper.append(document.body,
50910 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
50913 this.closable = false;
50914 this.loaded = false;
50915 this.active = false;
50916 if(typeof config == "string"){
50917 this.title = config;
50919 Roo.apply(this, config);
50922 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
50923 this.wrapEl = this.el.wrap();
50924 this.toolbar.container = this.el.insertSibling(false, 'before');
50925 this.toolbar = new Roo.Toolbar(this.toolbar);
50928 // xtype created footer. - not sure if will work as we normally have to render first..
50929 if (this.footer && !this.footer.el && this.footer.xtype) {
50930 if (!this.wrapEl) {
50931 this.wrapEl = this.el.wrap();
50934 this.footer.container = this.wrapEl.createChild();
50936 this.footer = Roo.factory(this.footer, Roo);
50941 this.resizeEl = Roo.get(this.resizeEl, true);
50943 this.resizeEl = this.el;
50945 // handle view.xtype
50953 * Fires when this panel is activated.
50954 * @param {Roo.ContentPanel} this
50958 * @event deactivate
50959 * Fires when this panel is activated.
50960 * @param {Roo.ContentPanel} this
50962 "deactivate" : true,
50966 * Fires when this panel is resized if fitToFrame is true.
50967 * @param {Roo.ContentPanel} this
50968 * @param {Number} width The width after any component adjustments
50969 * @param {Number} height The height after any component adjustments
50975 * Fires when this tab is created
50976 * @param {Roo.ContentPanel} this
50987 if(this.autoScroll){
50988 this.resizeEl.setStyle("overflow", "auto");
50990 // fix randome scrolling
50991 this.el.on('scroll', function() {
50992 Roo.log('fix random scolling');
50993 this.scrollTo('top',0);
50996 content = content || this.content;
50998 this.setContent(content);
51000 if(config && config.url){
51001 this.setUrl(this.url, this.params, this.loadOnce);
51006 Roo.ContentPanel.superclass.constructor.call(this);
51008 if (this.view && typeof(this.view.xtype) != 'undefined') {
51009 this.view.el = this.el.appendChild(document.createElement("div"));
51010 this.view = Roo.factory(this.view);
51011 this.view.render && this.view.render(false, '');
51015 this.fireEvent('render', this);
51018 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51020 setRegion : function(region){
51021 this.region = region;
51023 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51025 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51030 * Returns the toolbar for this Panel if one was configured.
51031 * @return {Roo.Toolbar}
51033 getToolbar : function(){
51034 return this.toolbar;
51037 setActiveState : function(active){
51038 this.active = active;
51040 this.fireEvent("deactivate", this);
51042 this.fireEvent("activate", this);
51046 * Updates this panel's element
51047 * @param {String} content The new content
51048 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51050 setContent : function(content, loadScripts){
51051 this.el.update(content, loadScripts);
51054 ignoreResize : function(w, h){
51055 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51058 this.lastSize = {width: w, height: h};
51063 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51064 * @return {Roo.UpdateManager} The UpdateManager
51066 getUpdateManager : function(){
51067 return this.el.getUpdateManager();
51070 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51071 * @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:
51074 url: "your-url.php",
51075 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51076 callback: yourFunction,
51077 scope: yourObject, //(optional scope)
51080 text: "Loading...",
51085 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51086 * 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.
51087 * @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}
51088 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51089 * @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.
51090 * @return {Roo.ContentPanel} this
51093 var um = this.el.getUpdateManager();
51094 um.update.apply(um, arguments);
51100 * 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.
51101 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51102 * @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)
51103 * @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)
51104 * @return {Roo.UpdateManager} The UpdateManager
51106 setUrl : function(url, params, loadOnce){
51107 if(this.refreshDelegate){
51108 this.removeListener("activate", this.refreshDelegate);
51110 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51111 this.on("activate", this.refreshDelegate);
51112 return this.el.getUpdateManager();
51115 _handleRefresh : function(url, params, loadOnce){
51116 if(!loadOnce || !this.loaded){
51117 var updater = this.el.getUpdateManager();
51118 updater.update(url, params, this._setLoaded.createDelegate(this));
51122 _setLoaded : function(){
51123 this.loaded = true;
51127 * Returns this panel's id
51130 getId : function(){
51135 * Returns this panel's element - used by regiosn to add.
51136 * @return {Roo.Element}
51138 getEl : function(){
51139 return this.wrapEl || this.el;
51142 adjustForComponents : function(width, height)
51144 //Roo.log('adjustForComponents ');
51145 if(this.resizeEl != this.el){
51146 width -= this.el.getFrameWidth('lr');
51147 height -= this.el.getFrameWidth('tb');
51150 var te = this.toolbar.getEl();
51151 height -= te.getHeight();
51152 te.setWidth(width);
51155 var te = this.footer.getEl();
51156 Roo.log("footer:" + te.getHeight());
51158 height -= te.getHeight();
51159 te.setWidth(width);
51163 if(this.adjustments){
51164 width += this.adjustments[0];
51165 height += this.adjustments[1];
51167 return {"width": width, "height": height};
51170 setSize : function(width, height){
51171 if(this.fitToFrame && !this.ignoreResize(width, height)){
51172 if(this.fitContainer && this.resizeEl != this.el){
51173 this.el.setSize(width, height);
51175 var size = this.adjustForComponents(width, height);
51176 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51177 this.fireEvent('resize', this, size.width, size.height);
51182 * Returns this panel's title
51185 getTitle : function(){
51190 * Set this panel's title
51191 * @param {String} title
51193 setTitle : function(title){
51194 this.title = title;
51196 this.region.updatePanelTitle(this, title);
51201 * Returns true is this panel was configured to be closable
51202 * @return {Boolean}
51204 isClosable : function(){
51205 return this.closable;
51208 beforeSlide : function(){
51210 this.resizeEl.clip();
51213 afterSlide : function(){
51215 this.resizeEl.unclip();
51219 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51220 * Will fail silently if the {@link #setUrl} method has not been called.
51221 * This does not activate the panel, just updates its content.
51223 refresh : function(){
51224 if(this.refreshDelegate){
51225 this.loaded = false;
51226 this.refreshDelegate();
51231 * Destroys this panel
51233 destroy : function(){
51234 this.el.removeAllListeners();
51235 var tempEl = document.createElement("span");
51236 tempEl.appendChild(this.el.dom);
51237 tempEl.innerHTML = "";
51243 * form - if the content panel contains a form - this is a reference to it.
51244 * @type {Roo.form.Form}
51248 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51249 * This contains a reference to it.
51255 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51265 * @param {Object} cfg Xtype definition of item to add.
51268 addxtype : function(cfg) {
51270 if (cfg.xtype.match(/^Form$/)) {
51273 //if (this.footer) {
51274 // el = this.footer.container.insertSibling(false, 'before');
51276 el = this.el.createChild();
51279 this.form = new Roo.form.Form(cfg);
51282 if ( this.form.allItems.length) this.form.render(el.dom);
51285 // should only have one of theses..
51286 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51287 // views.. should not be just added - used named prop 'view''
51289 cfg.el = this.el.appendChild(document.createElement("div"));
51292 var ret = new Roo.factory(cfg);
51294 ret.render && ret.render(false, ''); // render blank..
51303 * @class Roo.GridPanel
51304 * @extends Roo.ContentPanel
51306 * Create a new GridPanel.
51307 * @param {Roo.grid.Grid} grid The grid for this panel
51308 * @param {String/Object} config A string to set only the panel's title, or a config object
51310 Roo.GridPanel = function(grid, config){
51313 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51314 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51316 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51318 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51321 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51323 // xtype created footer. - not sure if will work as we normally have to render first..
51324 if (this.footer && !this.footer.el && this.footer.xtype) {
51326 this.footer.container = this.grid.getView().getFooterPanel(true);
51327 this.footer.dataSource = this.grid.dataSource;
51328 this.footer = Roo.factory(this.footer, Roo);
51332 grid.monitorWindowResize = false; // turn off autosizing
51333 grid.autoHeight = false;
51334 grid.autoWidth = false;
51336 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51339 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51340 getId : function(){
51341 return this.grid.id;
51345 * Returns the grid for this panel
51346 * @return {Roo.grid.Grid}
51348 getGrid : function(){
51352 setSize : function(width, height){
51353 if(!this.ignoreResize(width, height)){
51354 var grid = this.grid;
51355 var size = this.adjustForComponents(width, height);
51356 grid.getGridEl().setSize(size.width, size.height);
51361 beforeSlide : function(){
51362 this.grid.getView().scroller.clip();
51365 afterSlide : function(){
51366 this.grid.getView().scroller.unclip();
51369 destroy : function(){
51370 this.grid.destroy();
51372 Roo.GridPanel.superclass.destroy.call(this);
51378 * @class Roo.NestedLayoutPanel
51379 * @extends Roo.ContentPanel
51381 * Create a new NestedLayoutPanel.
51384 * @param {Roo.BorderLayout} layout The layout for this panel
51385 * @param {String/Object} config A string to set only the title or a config object
51387 Roo.NestedLayoutPanel = function(layout, config)
51389 // construct with only one argument..
51390 /* FIXME - implement nicer consturctors
51391 if (layout.layout) {
51393 layout = config.layout;
51394 delete config.layout;
51396 if (layout.xtype && !layout.getEl) {
51397 // then layout needs constructing..
51398 layout = Roo.factory(layout, Roo);
51403 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51405 layout.monitorWindowResize = false; // turn off autosizing
51406 this.layout = layout;
51407 this.layout.getEl().addClass("x-layout-nested-layout");
51414 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51416 setSize : function(width, height){
51417 if(!this.ignoreResize(width, height)){
51418 var size = this.adjustForComponents(width, height);
51419 var el = this.layout.getEl();
51420 el.setSize(size.width, size.height);
51421 var touch = el.dom.offsetWidth;
51422 this.layout.layout();
51423 // ie requires a double layout on the first pass
51424 if(Roo.isIE && !this.initialized){
51425 this.initialized = true;
51426 this.layout.layout();
51431 // activate all subpanels if not currently active..
51433 setActiveState : function(active){
51434 this.active = active;
51436 this.fireEvent("deactivate", this);
51440 this.fireEvent("activate", this);
51441 // not sure if this should happen before or after..
51442 if (!this.layout) {
51443 return; // should not happen..
51446 for (var r in this.layout.regions) {
51447 reg = this.layout.getRegion(r);
51448 if (reg.getActivePanel()) {
51449 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51450 reg.setActivePanel(reg.getActivePanel());
51453 if (!reg.panels.length) {
51456 reg.showPanel(reg.getPanel(0));
51465 * Returns the nested BorderLayout for this panel
51466 * @return {Roo.BorderLayout}
51468 getLayout : function(){
51469 return this.layout;
51473 * Adds a xtype elements to the layout of the nested panel
51477 xtype : 'ContentPanel',
51484 xtype : 'NestedLayoutPanel',
51490 items : [ ... list of content panels or nested layout panels.. ]
51494 * @param {Object} cfg Xtype definition of item to add.
51496 addxtype : function(cfg) {
51497 return this.layout.addxtype(cfg);
51502 Roo.ScrollPanel = function(el, config, content){
51503 config = config || {};
51504 config.fitToFrame = true;
51505 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
51507 this.el.dom.style.overflow = "hidden";
51508 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
51509 this.el.removeClass("x-layout-inactive-content");
51510 this.el.on("mousewheel", this.onWheel, this);
51512 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
51513 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
51514 up.unselectable(); down.unselectable();
51515 up.on("click", this.scrollUp, this);
51516 down.on("click", this.scrollDown, this);
51517 up.addClassOnOver("x-scroller-btn-over");
51518 down.addClassOnOver("x-scroller-btn-over");
51519 up.addClassOnClick("x-scroller-btn-click");
51520 down.addClassOnClick("x-scroller-btn-click");
51521 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
51523 this.resizeEl = this.el;
51524 this.el = wrap; this.up = up; this.down = down;
51527 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
51529 wheelIncrement : 5,
51530 scrollUp : function(){
51531 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
51534 scrollDown : function(){
51535 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
51538 afterScroll : function(){
51539 var el = this.resizeEl;
51540 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
51541 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51542 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51545 setSize : function(){
51546 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
51547 this.afterScroll();
51550 onWheel : function(e){
51551 var d = e.getWheelDelta();
51552 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
51553 this.afterScroll();
51557 setContent : function(content, loadScripts){
51558 this.resizeEl.update(content, loadScripts);
51572 * @class Roo.TreePanel
51573 * @extends Roo.ContentPanel
51575 * Create a new TreePanel. - defaults to fit/scoll contents.
51576 * @param {String/Object} config A string to set only the panel's title, or a config object
51577 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
51579 Roo.TreePanel = function(config){
51580 var el = config.el;
51581 var tree = config.tree;
51582 delete config.tree;
51583 delete config.el; // hopefull!
51585 // wrapper for IE7 strict & safari scroll issue
51587 var treeEl = el.createChild();
51588 config.resizeEl = treeEl;
51592 Roo.TreePanel.superclass.constructor.call(this, el, config);
51595 this.tree = new Roo.tree.TreePanel(treeEl , tree);
51596 //console.log(tree);
51597 this.on('activate', function()
51599 if (this.tree.rendered) {
51602 //console.log('render tree');
51603 this.tree.render();
51605 // this should not be needed.. - it's actually the 'el' that resizes?
51606 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
51608 //this.on('resize', function (cp, w, h) {
51609 // this.tree.innerCt.setWidth(w);
51610 // this.tree.innerCt.setHeight(h);
51611 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
51618 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
51635 * Ext JS Library 1.1.1
51636 * Copyright(c) 2006-2007, Ext JS, LLC.
51638 * Originally Released Under LGPL - original licence link has changed is not relivant.
51641 * <script type="text/javascript">
51646 * @class Roo.ReaderLayout
51647 * @extends Roo.BorderLayout
51648 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
51649 * center region containing two nested regions (a top one for a list view and one for item preview below),
51650 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
51651 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
51652 * expedites the setup of the overall layout and regions for this common application style.
51655 var reader = new Roo.ReaderLayout();
51656 var CP = Roo.ContentPanel; // shortcut for adding
51658 reader.beginUpdate();
51659 reader.add("north", new CP("north", "North"));
51660 reader.add("west", new CP("west", {title: "West"}));
51661 reader.add("east", new CP("east", {title: "East"}));
51663 reader.regions.listView.add(new CP("listView", "List"));
51664 reader.regions.preview.add(new CP("preview", "Preview"));
51665 reader.endUpdate();
51668 * Create a new ReaderLayout
51669 * @param {Object} config Configuration options
51670 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
51671 * document.body if omitted)
51673 Roo.ReaderLayout = function(config, renderTo){
51674 var c = config || {size:{}};
51675 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
51676 north: c.north !== false ? Roo.apply({
51680 }, c.north) : false,
51681 west: c.west !== false ? Roo.apply({
51689 margins:{left:5,right:0,bottom:5,top:5},
51690 cmargins:{left:5,right:5,bottom:5,top:5}
51691 }, c.west) : false,
51692 east: c.east !== false ? Roo.apply({
51700 margins:{left:0,right:5,bottom:5,top:5},
51701 cmargins:{left:5,right:5,bottom:5,top:5}
51702 }, c.east) : false,
51703 center: Roo.apply({
51704 tabPosition: 'top',
51708 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
51712 this.el.addClass('x-reader');
51714 this.beginUpdate();
51716 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
51717 south: c.preview !== false ? Roo.apply({
51724 cmargins:{top:5,left:0, right:0, bottom:0}
51725 }, c.preview) : false,
51726 center: Roo.apply({
51732 this.add('center', new Roo.NestedLayoutPanel(inner,
51733 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
51737 this.regions.preview = inner.getRegion('south');
51738 this.regions.listView = inner.getRegion('center');
51741 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
51743 * Ext JS Library 1.1.1
51744 * Copyright(c) 2006-2007, Ext JS, LLC.
51746 * Originally Released Under LGPL - original licence link has changed is not relivant.
51749 * <script type="text/javascript">
51753 * @class Roo.grid.Grid
51754 * @extends Roo.util.Observable
51755 * This class represents the primary interface of a component based grid control.
51756 * <br><br>Usage:<pre><code>
51757 var grid = new Roo.grid.Grid("my-container-id", {
51760 selModel: mySelectionModel,
51761 autoSizeColumns: true,
51762 monitorWindowResize: false,
51763 trackMouseOver: true
51768 * <b>Common Problems:</b><br/>
51769 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
51770 * element will correct this<br/>
51771 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
51772 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
51773 * are unpredictable.<br/>
51774 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
51775 * grid to calculate dimensions/offsets.<br/>
51777 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51778 * The container MUST have some type of size defined for the grid to fill. The container will be
51779 * automatically set to position relative if it isn't already.
51780 * @param {Object} config A config object that sets properties on this grid.
51782 Roo.grid.Grid = function(container, config){
51783 // initialize the container
51784 this.container = Roo.get(container);
51785 this.container.update("");
51786 this.container.setStyle("overflow", "hidden");
51787 this.container.addClass('x-grid-container');
51789 this.id = this.container.id;
51791 Roo.apply(this, config);
51792 // check and correct shorthanded configs
51794 this.dataSource = this.ds;
51798 this.colModel = this.cm;
51802 this.selModel = this.sm;
51806 if (this.selModel) {
51807 this.selModel = Roo.factory(this.selModel, Roo.grid);
51808 this.sm = this.selModel;
51809 this.sm.xmodule = this.xmodule || false;
51811 if (typeof(this.colModel.config) == 'undefined') {
51812 this.colModel = new Roo.grid.ColumnModel(this.colModel);
51813 this.cm = this.colModel;
51814 this.cm.xmodule = this.xmodule || false;
51816 if (this.dataSource) {
51817 this.dataSource= Roo.factory(this.dataSource, Roo.data);
51818 this.ds = this.dataSource;
51819 this.ds.xmodule = this.xmodule || false;
51826 this.container.setWidth(this.width);
51830 this.container.setHeight(this.height);
51837 * The raw click event for the entire grid.
51838 * @param {Roo.EventObject} e
51843 * The raw dblclick event for the entire grid.
51844 * @param {Roo.EventObject} e
51848 * @event contextmenu
51849 * The raw contextmenu event for the entire grid.
51850 * @param {Roo.EventObject} e
51852 "contextmenu" : true,
51855 * The raw mousedown event for the entire grid.
51856 * @param {Roo.EventObject} e
51858 "mousedown" : true,
51861 * The raw mouseup event for the entire grid.
51862 * @param {Roo.EventObject} e
51867 * The raw mouseover event for the entire grid.
51868 * @param {Roo.EventObject} e
51870 "mouseover" : true,
51873 * The raw mouseout event for the entire grid.
51874 * @param {Roo.EventObject} e
51879 * The raw keypress event for the entire grid.
51880 * @param {Roo.EventObject} e
51885 * The raw keydown event for the entire grid.
51886 * @param {Roo.EventObject} e
51894 * Fires when a cell is clicked
51895 * @param {Grid} this
51896 * @param {Number} rowIndex
51897 * @param {Number} columnIndex
51898 * @param {Roo.EventObject} e
51900 "cellclick" : true,
51902 * @event celldblclick
51903 * Fires when a cell is double clicked
51904 * @param {Grid} this
51905 * @param {Number} rowIndex
51906 * @param {Number} columnIndex
51907 * @param {Roo.EventObject} e
51909 "celldblclick" : true,
51912 * Fires when a row is clicked
51913 * @param {Grid} this
51914 * @param {Number} rowIndex
51915 * @param {Roo.EventObject} e
51919 * @event rowdblclick
51920 * Fires when a row is double clicked
51921 * @param {Grid} this
51922 * @param {Number} rowIndex
51923 * @param {Roo.EventObject} e
51925 "rowdblclick" : true,
51927 * @event headerclick
51928 * Fires when a header is clicked
51929 * @param {Grid} this
51930 * @param {Number} columnIndex
51931 * @param {Roo.EventObject} e
51933 "headerclick" : true,
51935 * @event headerdblclick
51936 * Fires when a header cell is double clicked
51937 * @param {Grid} this
51938 * @param {Number} columnIndex
51939 * @param {Roo.EventObject} e
51941 "headerdblclick" : true,
51943 * @event rowcontextmenu
51944 * Fires when a row is right clicked
51945 * @param {Grid} this
51946 * @param {Number} rowIndex
51947 * @param {Roo.EventObject} e
51949 "rowcontextmenu" : true,
51951 * @event cellcontextmenu
51952 * Fires when a cell is right clicked
51953 * @param {Grid} this
51954 * @param {Number} rowIndex
51955 * @param {Number} cellIndex
51956 * @param {Roo.EventObject} e
51958 "cellcontextmenu" : true,
51960 * @event headercontextmenu
51961 * Fires when a header is right clicked
51962 * @param {Grid} this
51963 * @param {Number} columnIndex
51964 * @param {Roo.EventObject} e
51966 "headercontextmenu" : true,
51968 * @event bodyscroll
51969 * Fires when the body element is scrolled
51970 * @param {Number} scrollLeft
51971 * @param {Number} scrollTop
51973 "bodyscroll" : true,
51975 * @event columnresize
51976 * Fires when the user resizes a column
51977 * @param {Number} columnIndex
51978 * @param {Number} newSize
51980 "columnresize" : true,
51982 * @event columnmove
51983 * Fires when the user moves a column
51984 * @param {Number} oldIndex
51985 * @param {Number} newIndex
51987 "columnmove" : true,
51990 * Fires when row(s) start being dragged
51991 * @param {Grid} this
51992 * @param {Roo.GridDD} dd The drag drop object
51993 * @param {event} e The raw browser event
51995 "startdrag" : true,
51998 * Fires when a drag operation is complete
51999 * @param {Grid} this
52000 * @param {Roo.GridDD} dd The drag drop object
52001 * @param {event} e The raw browser event
52006 * Fires when dragged row(s) are dropped on a valid DD target
52007 * @param {Grid} this
52008 * @param {Roo.GridDD} dd The drag drop object
52009 * @param {String} targetId The target drag drop object
52010 * @param {event} e The raw browser event
52015 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52016 * @param {Grid} this
52017 * @param {Roo.GridDD} dd The drag drop object
52018 * @param {String} targetId The target drag drop object
52019 * @param {event} e The raw browser event
52024 * Fires when the dragged row(s) first cross another DD target while being dragged
52025 * @param {Grid} this
52026 * @param {Roo.GridDD} dd The drag drop object
52027 * @param {String} targetId The target drag drop object
52028 * @param {event} e The raw browser event
52030 "dragenter" : true,
52033 * Fires when the dragged row(s) leave another DD target while being dragged
52034 * @param {Grid} this
52035 * @param {Roo.GridDD} dd The drag drop object
52036 * @param {String} targetId The target drag drop object
52037 * @param {event} e The raw browser event
52042 * Fires when a row is rendered, so you can change add a style to it.
52043 * @param {GridView} gridview The grid view
52044 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52050 * Fires when the grid is rendered
52051 * @param {Grid} grid
52056 Roo.grid.Grid.superclass.constructor.call(this);
52058 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52061 * @cfg {String} ddGroup - drag drop group.
52065 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52067 minColumnWidth : 25,
52070 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52071 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52072 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52074 autoSizeColumns : false,
52077 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52079 autoSizeHeaders : true,
52082 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52084 monitorWindowResize : true,
52087 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52088 * rows measured to get a columns size. Default is 0 (all rows).
52090 maxRowsToMeasure : 0,
52093 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52095 trackMouseOver : true,
52098 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52102 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52104 enableDragDrop : false,
52107 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52109 enableColumnMove : true,
52112 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52114 enableColumnHide : true,
52117 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52119 enableRowHeightSync : false,
52122 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52127 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52129 autoHeight : false,
52132 * @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.
52134 autoExpandColumn : false,
52137 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52140 autoExpandMin : 50,
52143 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52145 autoExpandMax : 1000,
52148 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52153 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52157 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52167 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52168 * of a fixed width. Default is false.
52171 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52174 * Called once after all setup has been completed and the grid is ready to be rendered.
52175 * @return {Roo.grid.Grid} this
52177 render : function()
52179 var c = this.container;
52180 // try to detect autoHeight/width mode
52181 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52182 this.autoHeight = true;
52184 var view = this.getView();
52187 c.on("click", this.onClick, this);
52188 c.on("dblclick", this.onDblClick, this);
52189 c.on("contextmenu", this.onContextMenu, this);
52190 c.on("keydown", this.onKeyDown, this);
52192 c.on("touchstart", this.onTouchStart, this);
52195 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52197 this.getSelectionModel().init(this);
52202 this.loadMask = new Roo.LoadMask(this.container,
52203 Roo.apply({store:this.dataSource}, this.loadMask));
52207 if (this.toolbar && this.toolbar.xtype) {
52208 this.toolbar.container = this.getView().getHeaderPanel(true);
52209 this.toolbar = new Roo.Toolbar(this.toolbar);
52211 if (this.footer && this.footer.xtype) {
52212 this.footer.dataSource = this.getDataSource();
52213 this.footer.container = this.getView().getFooterPanel(true);
52214 this.footer = Roo.factory(this.footer, Roo);
52216 if (this.dropTarget && this.dropTarget.xtype) {
52217 delete this.dropTarget.xtype;
52218 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52222 this.rendered = true;
52223 this.fireEvent('render', this);
52228 * Reconfigures the grid to use a different Store and Column Model.
52229 * The View will be bound to the new objects and refreshed.
52230 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52231 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52233 reconfigure : function(dataSource, colModel){
52235 this.loadMask.destroy();
52236 this.loadMask = new Roo.LoadMask(this.container,
52237 Roo.apply({store:dataSource}, this.loadMask));
52239 this.view.bind(dataSource, colModel);
52240 this.dataSource = dataSource;
52241 this.colModel = colModel;
52242 this.view.refresh(true);
52246 onKeyDown : function(e){
52247 this.fireEvent("keydown", e);
52251 * Destroy this grid.
52252 * @param {Boolean} removeEl True to remove the element
52254 destroy : function(removeEl, keepListeners){
52256 this.loadMask.destroy();
52258 var c = this.container;
52259 c.removeAllListeners();
52260 this.view.destroy();
52261 this.colModel.purgeListeners();
52262 if(!keepListeners){
52263 this.purgeListeners();
52266 if(removeEl === true){
52272 processEvent : function(name, e){
52273 // does this fire select???
52274 Roo.log('grid:processEvent ' + name);
52276 if (name != 'touchstart' ) {
52277 this.fireEvent(name, e);
52280 var t = e.getTarget();
52282 var header = v.findHeaderIndex(t);
52283 if(header !== false){
52284 var ename = name == 'touchstart' ? 'click' : name;
52286 this.fireEvent("header" + ename, this, header, e);
52288 var row = v.findRowIndex(t);
52289 var cell = v.findCellIndex(t);
52290 if (name == 'touchstart') {
52291 // first touch is always a click.
52292 // hopefull this happens after selection is updated.?
52295 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52296 var cs = this.selModel.getSelectedCell();
52297 if (row == cs[0] && cell == cs[1]){
52301 if (typeof(this.selModel.getSelections) != 'undefined') {
52302 var cs = this.selModel.getSelections();
52303 var ds = this.dataSource;
52304 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52315 this.fireEvent("row" + name, this, row, e);
52316 if(cell !== false){
52317 this.fireEvent("cell" + name, this, row, cell, e);
52324 onClick : function(e){
52325 this.processEvent("click", e);
52328 onTouchStart : function(e){
52329 this.processEvent("touchstart", e);
52333 onContextMenu : function(e, t){
52334 this.processEvent("contextmenu", e);
52338 onDblClick : function(e){
52339 this.processEvent("dblclick", e);
52343 walkCells : function(row, col, step, fn, scope){
52344 var cm = this.colModel, clen = cm.getColumnCount();
52345 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52357 if(fn.call(scope || this, row, col, cm) === true){
52375 if(fn.call(scope || this, row, col, cm) === true){
52387 getSelections : function(){
52388 return this.selModel.getSelections();
52392 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52393 * but if manual update is required this method will initiate it.
52395 autoSize : function(){
52397 this.view.layout();
52398 if(this.view.adjustForScroll){
52399 this.view.adjustForScroll();
52405 * Returns the grid's underlying element.
52406 * @return {Element} The element
52408 getGridEl : function(){
52409 return this.container;
52412 // private for compatibility, overridden by editor grid
52413 stopEditing : function(){},
52416 * Returns the grid's SelectionModel.
52417 * @return {SelectionModel}
52419 getSelectionModel : function(){
52420 if(!this.selModel){
52421 this.selModel = new Roo.grid.RowSelectionModel();
52423 return this.selModel;
52427 * Returns the grid's DataSource.
52428 * @return {DataSource}
52430 getDataSource : function(){
52431 return this.dataSource;
52435 * Returns the grid's ColumnModel.
52436 * @return {ColumnModel}
52438 getColumnModel : function(){
52439 return this.colModel;
52443 * Returns the grid's GridView object.
52444 * @return {GridView}
52446 getView : function(){
52448 this.view = new Roo.grid.GridView(this.viewConfig);
52453 * Called to get grid's drag proxy text, by default returns this.ddText.
52456 getDragDropText : function(){
52457 var count = this.selModel.getCount();
52458 return String.format(this.ddText, count, count == 1 ? '' : 's');
52462 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
52463 * %0 is replaced with the number of selected rows.
52466 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
52468 * Ext JS Library 1.1.1
52469 * Copyright(c) 2006-2007, Ext JS, LLC.
52471 * Originally Released Under LGPL - original licence link has changed is not relivant.
52474 * <script type="text/javascript">
52477 Roo.grid.AbstractGridView = function(){
52481 "beforerowremoved" : true,
52482 "beforerowsinserted" : true,
52483 "beforerefresh" : true,
52484 "rowremoved" : true,
52485 "rowsinserted" : true,
52486 "rowupdated" : true,
52489 Roo.grid.AbstractGridView.superclass.constructor.call(this);
52492 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
52493 rowClass : "x-grid-row",
52494 cellClass : "x-grid-cell",
52495 tdClass : "x-grid-td",
52496 hdClass : "x-grid-hd",
52497 splitClass : "x-grid-hd-split",
52499 init: function(grid){
52501 var cid = this.grid.getGridEl().id;
52502 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
52503 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
52504 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
52505 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
52508 getColumnRenderers : function(){
52509 var renderers = [];
52510 var cm = this.grid.colModel;
52511 var colCount = cm.getColumnCount();
52512 for(var i = 0; i < colCount; i++){
52513 renderers[i] = cm.getRenderer(i);
52518 getColumnIds : function(){
52520 var cm = this.grid.colModel;
52521 var colCount = cm.getColumnCount();
52522 for(var i = 0; i < colCount; i++){
52523 ids[i] = cm.getColumnId(i);
52528 getDataIndexes : function(){
52529 if(!this.indexMap){
52530 this.indexMap = this.buildIndexMap();
52532 return this.indexMap.colToData;
52535 getColumnIndexByDataIndex : function(dataIndex){
52536 if(!this.indexMap){
52537 this.indexMap = this.buildIndexMap();
52539 return this.indexMap.dataToCol[dataIndex];
52543 * Set a css style for a column dynamically.
52544 * @param {Number} colIndex The index of the column
52545 * @param {String} name The css property name
52546 * @param {String} value The css value
52548 setCSSStyle : function(colIndex, name, value){
52549 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
52550 Roo.util.CSS.updateRule(selector, name, value);
52553 generateRules : function(cm){
52554 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
52555 Roo.util.CSS.removeStyleSheet(rulesId);
52556 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52557 var cid = cm.getColumnId(i);
52558 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
52559 this.tdSelector, cid, " {\n}\n",
52560 this.hdSelector, cid, " {\n}\n",
52561 this.splitSelector, cid, " {\n}\n");
52563 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52567 * Ext JS Library 1.1.1
52568 * Copyright(c) 2006-2007, Ext JS, LLC.
52570 * Originally Released Under LGPL - original licence link has changed is not relivant.
52573 * <script type="text/javascript">
52577 // This is a support class used internally by the Grid components
52578 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
52580 this.view = grid.getView();
52581 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52582 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
52584 this.setHandleElId(Roo.id(hd));
52585 this.setOuterHandleElId(Roo.id(hd2));
52587 this.scroll = false;
52589 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
52591 getDragData : function(e){
52592 var t = Roo.lib.Event.getTarget(e);
52593 var h = this.view.findHeaderCell(t);
52595 return {ddel: h.firstChild, header:h};
52600 onInitDrag : function(e){
52601 this.view.headersDisabled = true;
52602 var clone = this.dragData.ddel.cloneNode(true);
52603 clone.id = Roo.id();
52604 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
52605 this.proxy.update(clone);
52609 afterValidDrop : function(){
52611 setTimeout(function(){
52612 v.headersDisabled = false;
52616 afterInvalidDrop : function(){
52618 setTimeout(function(){
52619 v.headersDisabled = false;
52625 * Ext JS Library 1.1.1
52626 * Copyright(c) 2006-2007, Ext JS, LLC.
52628 * Originally Released Under LGPL - original licence link has changed is not relivant.
52631 * <script type="text/javascript">
52634 // This is a support class used internally by the Grid components
52635 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
52637 this.view = grid.getView();
52638 // split the proxies so they don't interfere with mouse events
52639 this.proxyTop = Roo.DomHelper.append(document.body, {
52640 cls:"col-move-top", html:" "
52642 this.proxyBottom = Roo.DomHelper.append(document.body, {
52643 cls:"col-move-bottom", html:" "
52645 this.proxyTop.hide = this.proxyBottom.hide = function(){
52646 this.setLeftTop(-100,-100);
52647 this.setStyle("visibility", "hidden");
52649 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52650 // temporarily disabled
52651 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
52652 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
52654 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
52655 proxyOffsets : [-4, -9],
52656 fly: Roo.Element.fly,
52658 getTargetFromEvent : function(e){
52659 var t = Roo.lib.Event.getTarget(e);
52660 var cindex = this.view.findCellIndex(t);
52661 if(cindex !== false){
52662 return this.view.getHeaderCell(cindex);
52667 nextVisible : function(h){
52668 var v = this.view, cm = this.grid.colModel;
52671 if(!cm.isHidden(v.getCellIndex(h))){
52679 prevVisible : function(h){
52680 var v = this.view, cm = this.grid.colModel;
52683 if(!cm.isHidden(v.getCellIndex(h))){
52691 positionIndicator : function(h, n, e){
52692 var x = Roo.lib.Event.getPageX(e);
52693 var r = Roo.lib.Dom.getRegion(n.firstChild);
52694 var px, pt, py = r.top + this.proxyOffsets[1];
52695 if((r.right - x) <= (r.right-r.left)/2){
52696 px = r.right+this.view.borderWidth;
52702 var oldIndex = this.view.getCellIndex(h);
52703 var newIndex = this.view.getCellIndex(n);
52705 if(this.grid.colModel.isFixed(newIndex)){
52709 var locked = this.grid.colModel.isLocked(newIndex);
52714 if(oldIndex < newIndex){
52717 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
52720 px += this.proxyOffsets[0];
52721 this.proxyTop.setLeftTop(px, py);
52722 this.proxyTop.show();
52723 if(!this.bottomOffset){
52724 this.bottomOffset = this.view.mainHd.getHeight();
52726 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
52727 this.proxyBottom.show();
52731 onNodeEnter : function(n, dd, e, data){
52732 if(data.header != n){
52733 this.positionIndicator(data.header, n, e);
52737 onNodeOver : function(n, dd, e, data){
52738 var result = false;
52739 if(data.header != n){
52740 result = this.positionIndicator(data.header, n, e);
52743 this.proxyTop.hide();
52744 this.proxyBottom.hide();
52746 return result ? this.dropAllowed : this.dropNotAllowed;
52749 onNodeOut : function(n, dd, e, data){
52750 this.proxyTop.hide();
52751 this.proxyBottom.hide();
52754 onNodeDrop : function(n, dd, e, data){
52755 var h = data.header;
52757 var cm = this.grid.colModel;
52758 var x = Roo.lib.Event.getPageX(e);
52759 var r = Roo.lib.Dom.getRegion(n.firstChild);
52760 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
52761 var oldIndex = this.view.getCellIndex(h);
52762 var newIndex = this.view.getCellIndex(n);
52763 var locked = cm.isLocked(newIndex);
52767 if(oldIndex < newIndex){
52770 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
52773 cm.setLocked(oldIndex, locked, true);
52774 cm.moveColumn(oldIndex, newIndex);
52775 this.grid.fireEvent("columnmove", oldIndex, newIndex);
52783 * Ext JS Library 1.1.1
52784 * Copyright(c) 2006-2007, Ext JS, LLC.
52786 * Originally Released Under LGPL - original licence link has changed is not relivant.
52789 * <script type="text/javascript">
52793 * @class Roo.grid.GridView
52794 * @extends Roo.util.Observable
52797 * @param {Object} config
52799 Roo.grid.GridView = function(config){
52800 Roo.grid.GridView.superclass.constructor.call(this);
52803 Roo.apply(this, config);
52806 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
52808 unselectable : 'unselectable="on"',
52809 unselectableCls : 'x-unselectable',
52812 rowClass : "x-grid-row",
52814 cellClass : "x-grid-col",
52816 tdClass : "x-grid-td",
52818 hdClass : "x-grid-hd",
52820 splitClass : "x-grid-split",
52822 sortClasses : ["sort-asc", "sort-desc"],
52824 enableMoveAnim : false,
52828 dh : Roo.DomHelper,
52830 fly : Roo.Element.fly,
52832 css : Roo.util.CSS,
52838 scrollIncrement : 22,
52840 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
52842 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
52844 bind : function(ds, cm){
52846 this.ds.un("load", this.onLoad, this);
52847 this.ds.un("datachanged", this.onDataChange, this);
52848 this.ds.un("add", this.onAdd, this);
52849 this.ds.un("remove", this.onRemove, this);
52850 this.ds.un("update", this.onUpdate, this);
52851 this.ds.un("clear", this.onClear, this);
52854 ds.on("load", this.onLoad, this);
52855 ds.on("datachanged", this.onDataChange, this);
52856 ds.on("add", this.onAdd, this);
52857 ds.on("remove", this.onRemove, this);
52858 ds.on("update", this.onUpdate, this);
52859 ds.on("clear", this.onClear, this);
52864 this.cm.un("widthchange", this.onColWidthChange, this);
52865 this.cm.un("headerchange", this.onHeaderChange, this);
52866 this.cm.un("hiddenchange", this.onHiddenChange, this);
52867 this.cm.un("columnmoved", this.onColumnMove, this);
52868 this.cm.un("columnlockchange", this.onColumnLock, this);
52871 this.generateRules(cm);
52872 cm.on("widthchange", this.onColWidthChange, this);
52873 cm.on("headerchange", this.onHeaderChange, this);
52874 cm.on("hiddenchange", this.onHiddenChange, this);
52875 cm.on("columnmoved", this.onColumnMove, this);
52876 cm.on("columnlockchange", this.onColumnLock, this);
52881 init: function(grid){
52882 Roo.grid.GridView.superclass.init.call(this, grid);
52884 this.bind(grid.dataSource, grid.colModel);
52886 grid.on("headerclick", this.handleHeaderClick, this);
52888 if(grid.trackMouseOver){
52889 grid.on("mouseover", this.onRowOver, this);
52890 grid.on("mouseout", this.onRowOut, this);
52892 grid.cancelTextSelection = function(){};
52893 this.gridId = grid.id;
52895 var tpls = this.templates || {};
52898 tpls.master = new Roo.Template(
52899 '<div class="x-grid" hidefocus="true">',
52900 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
52901 '<div class="x-grid-topbar"></div>',
52902 '<div class="x-grid-scroller"><div></div></div>',
52903 '<div class="x-grid-locked">',
52904 '<div class="x-grid-header">{lockedHeader}</div>',
52905 '<div class="x-grid-body">{lockedBody}</div>',
52907 '<div class="x-grid-viewport">',
52908 '<div class="x-grid-header">{header}</div>',
52909 '<div class="x-grid-body">{body}</div>',
52911 '<div class="x-grid-bottombar"></div>',
52913 '<div class="x-grid-resize-proxy"> </div>',
52916 tpls.master.disableformats = true;
52920 tpls.header = new Roo.Template(
52921 '<table border="0" cellspacing="0" cellpadding="0">',
52922 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
52925 tpls.header.disableformats = true;
52927 tpls.header.compile();
52930 tpls.hcell = new Roo.Template(
52931 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
52932 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
52935 tpls.hcell.disableFormats = true;
52937 tpls.hcell.compile();
52940 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
52941 this.unselectableCls + '" ' + this.unselectable +'> </div>');
52942 tpls.hsplit.disableFormats = true;
52944 tpls.hsplit.compile();
52947 tpls.body = new Roo.Template(
52948 '<table border="0" cellspacing="0" cellpadding="0">',
52949 "<tbody>{rows}</tbody>",
52952 tpls.body.disableFormats = true;
52954 tpls.body.compile();
52957 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
52958 tpls.row.disableFormats = true;
52960 tpls.row.compile();
52963 tpls.cell = new Roo.Template(
52964 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
52965 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
52966 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
52969 tpls.cell.disableFormats = true;
52971 tpls.cell.compile();
52973 this.templates = tpls;
52976 // remap these for backwards compat
52977 onColWidthChange : function(){
52978 this.updateColumns.apply(this, arguments);
52980 onHeaderChange : function(){
52981 this.updateHeaders.apply(this, arguments);
52983 onHiddenChange : function(){
52984 this.handleHiddenChange.apply(this, arguments);
52986 onColumnMove : function(){
52987 this.handleColumnMove.apply(this, arguments);
52989 onColumnLock : function(){
52990 this.handleLockChange.apply(this, arguments);
52993 onDataChange : function(){
52995 this.updateHeaderSortState();
52998 onClear : function(){
53002 onUpdate : function(ds, record){
53003 this.refreshRow(record);
53006 refreshRow : function(record){
53007 var ds = this.ds, index;
53008 if(typeof record == 'number'){
53010 record = ds.getAt(index);
53012 index = ds.indexOf(record);
53014 this.insertRows(ds, index, index, true);
53015 this.onRemove(ds, record, index+1, true);
53016 this.syncRowHeights(index, index);
53018 this.fireEvent("rowupdated", this, index, record);
53021 onAdd : function(ds, records, index){
53022 this.insertRows(ds, index, index + (records.length-1));
53025 onRemove : function(ds, record, index, isUpdate){
53026 if(isUpdate !== true){
53027 this.fireEvent("beforerowremoved", this, index, record);
53029 var bt = this.getBodyTable(), lt = this.getLockedTable();
53030 if(bt.rows[index]){
53031 bt.firstChild.removeChild(bt.rows[index]);
53033 if(lt.rows[index]){
53034 lt.firstChild.removeChild(lt.rows[index]);
53036 if(isUpdate !== true){
53037 this.stripeRows(index);
53038 this.syncRowHeights(index, index);
53040 this.fireEvent("rowremoved", this, index, record);
53044 onLoad : function(){
53045 this.scrollToTop();
53049 * Scrolls the grid to the top
53051 scrollToTop : function(){
53053 this.scroller.dom.scrollTop = 0;
53059 * Gets a panel in the header of the grid that can be used for toolbars etc.
53060 * After modifying the contents of this panel a call to grid.autoSize() may be
53061 * required to register any changes in size.
53062 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53063 * @return Roo.Element
53065 getHeaderPanel : function(doShow){
53067 this.headerPanel.show();
53069 return this.headerPanel;
53073 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53074 * After modifying the contents of this panel a call to grid.autoSize() may be
53075 * required to register any changes in size.
53076 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53077 * @return Roo.Element
53079 getFooterPanel : function(doShow){
53081 this.footerPanel.show();
53083 return this.footerPanel;
53086 initElements : function(){
53087 var E = Roo.Element;
53088 var el = this.grid.getGridEl().dom.firstChild;
53089 var cs = el.childNodes;
53091 this.el = new E(el);
53093 this.focusEl = new E(el.firstChild);
53094 this.focusEl.swallowEvent("click", true);
53096 this.headerPanel = new E(cs[1]);
53097 this.headerPanel.enableDisplayMode("block");
53099 this.scroller = new E(cs[2]);
53100 this.scrollSizer = new E(this.scroller.dom.firstChild);
53102 this.lockedWrap = new E(cs[3]);
53103 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53104 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53106 this.mainWrap = new E(cs[4]);
53107 this.mainHd = new E(this.mainWrap.dom.firstChild);
53108 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53110 this.footerPanel = new E(cs[5]);
53111 this.footerPanel.enableDisplayMode("block");
53113 this.resizeProxy = new E(cs[6]);
53115 this.headerSelector = String.format(
53116 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53117 this.lockedHd.id, this.mainHd.id
53120 this.splitterSelector = String.format(
53121 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53122 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53125 idToCssName : function(s)
53127 return s.replace(/[^a-z0-9]+/ig, '-');
53130 getHeaderCell : function(index){
53131 return Roo.DomQuery.select(this.headerSelector)[index];
53134 getHeaderCellMeasure : function(index){
53135 return this.getHeaderCell(index).firstChild;
53138 getHeaderCellText : function(index){
53139 return this.getHeaderCell(index).firstChild.firstChild;
53142 getLockedTable : function(){
53143 return this.lockedBody.dom.firstChild;
53146 getBodyTable : function(){
53147 return this.mainBody.dom.firstChild;
53150 getLockedRow : function(index){
53151 return this.getLockedTable().rows[index];
53154 getRow : function(index){
53155 return this.getBodyTable().rows[index];
53158 getRowComposite : function(index){
53160 this.rowEl = new Roo.CompositeElementLite();
53162 var els = [], lrow, mrow;
53163 if(lrow = this.getLockedRow(index)){
53166 if(mrow = this.getRow(index)){
53169 this.rowEl.elements = els;
53173 * Gets the 'td' of the cell
53175 * @param {Integer} rowIndex row to select
53176 * @param {Integer} colIndex column to select
53180 getCell : function(rowIndex, colIndex){
53181 var locked = this.cm.getLockedCount();
53183 if(colIndex < locked){
53184 source = this.lockedBody.dom.firstChild;
53186 source = this.mainBody.dom.firstChild;
53187 colIndex -= locked;
53189 return source.rows[rowIndex].childNodes[colIndex];
53192 getCellText : function(rowIndex, colIndex){
53193 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53196 getCellBox : function(cell){
53197 var b = this.fly(cell).getBox();
53198 if(Roo.isOpera){ // opera fails to report the Y
53199 b.y = cell.offsetTop + this.mainBody.getY();
53204 getCellIndex : function(cell){
53205 var id = String(cell.className).match(this.cellRE);
53207 return parseInt(id[1], 10);
53212 findHeaderIndex : function(n){
53213 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53214 return r ? this.getCellIndex(r) : false;
53217 findHeaderCell : function(n){
53218 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53219 return r ? r : false;
53222 findRowIndex : function(n){
53226 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53227 return r ? r.rowIndex : false;
53230 findCellIndex : function(node){
53231 var stop = this.el.dom;
53232 while(node && node != stop){
53233 if(this.findRE.test(node.className)){
53234 return this.getCellIndex(node);
53236 node = node.parentNode;
53241 getColumnId : function(index){
53242 return this.cm.getColumnId(index);
53245 getSplitters : function()
53247 if(this.splitterSelector){
53248 return Roo.DomQuery.select(this.splitterSelector);
53254 getSplitter : function(index){
53255 return this.getSplitters()[index];
53258 onRowOver : function(e, t){
53260 if((row = this.findRowIndex(t)) !== false){
53261 this.getRowComposite(row).addClass("x-grid-row-over");
53265 onRowOut : function(e, t){
53267 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53268 this.getRowComposite(row).removeClass("x-grid-row-over");
53272 renderHeaders : function(){
53274 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53275 var cb = [], lb = [], sb = [], lsb = [], p = {};
53276 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53277 p.cellId = "x-grid-hd-0-" + i;
53278 p.splitId = "x-grid-csplit-0-" + i;
53279 p.id = cm.getColumnId(i);
53280 p.title = cm.getColumnTooltip(i) || "";
53281 p.value = cm.getColumnHeader(i) || "";
53282 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53283 if(!cm.isLocked(i)){
53284 cb[cb.length] = ct.apply(p);
53285 sb[sb.length] = st.apply(p);
53287 lb[lb.length] = ct.apply(p);
53288 lsb[lsb.length] = st.apply(p);
53291 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53292 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53295 updateHeaders : function(){
53296 var html = this.renderHeaders();
53297 this.lockedHd.update(html[0]);
53298 this.mainHd.update(html[1]);
53302 * Focuses the specified row.
53303 * @param {Number} row The row index
53305 focusRow : function(row)
53307 //Roo.log('GridView.focusRow');
53308 var x = this.scroller.dom.scrollLeft;
53309 this.focusCell(row, 0, false);
53310 this.scroller.dom.scrollLeft = x;
53314 * Focuses the specified cell.
53315 * @param {Number} row The row index
53316 * @param {Number} col The column index
53317 * @param {Boolean} hscroll false to disable horizontal scrolling
53319 focusCell : function(row, col, hscroll)
53321 //Roo.log('GridView.focusCell');
53322 var el = this.ensureVisible(row, col, hscroll);
53323 this.focusEl.alignTo(el, "tl-tl");
53325 this.focusEl.focus();
53327 this.focusEl.focus.defer(1, this.focusEl);
53332 * Scrolls the specified cell into view
53333 * @param {Number} row The row index
53334 * @param {Number} col The column index
53335 * @param {Boolean} hscroll false to disable horizontal scrolling
53337 ensureVisible : function(row, col, hscroll)
53339 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53340 //return null; //disable for testing.
53341 if(typeof row != "number"){
53342 row = row.rowIndex;
53344 if(row < 0 && row >= this.ds.getCount()){
53347 col = (col !== undefined ? col : 0);
53348 var cm = this.grid.colModel;
53349 while(cm.isHidden(col)){
53353 var el = this.getCell(row, col);
53357 var c = this.scroller.dom;
53359 var ctop = parseInt(el.offsetTop, 10);
53360 var cleft = parseInt(el.offsetLeft, 10);
53361 var cbot = ctop + el.offsetHeight;
53362 var cright = cleft + el.offsetWidth;
53364 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53365 var stop = parseInt(c.scrollTop, 10);
53366 var sleft = parseInt(c.scrollLeft, 10);
53367 var sbot = stop + ch;
53368 var sright = sleft + c.clientWidth;
53370 Roo.log('GridView.ensureVisible:' +
53372 ' c.clientHeight:' + c.clientHeight +
53373 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53381 c.scrollTop = ctop;
53382 //Roo.log("set scrolltop to ctop DISABLE?");
53383 }else if(cbot > sbot){
53384 //Roo.log("set scrolltop to cbot-ch");
53385 c.scrollTop = cbot-ch;
53388 if(hscroll !== false){
53390 c.scrollLeft = cleft;
53391 }else if(cright > sright){
53392 c.scrollLeft = cright-c.clientWidth;
53399 updateColumns : function(){
53400 this.grid.stopEditing();
53401 var cm = this.grid.colModel, colIds = this.getColumnIds();
53402 //var totalWidth = cm.getTotalWidth();
53404 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53405 //if(cm.isHidden(i)) continue;
53406 var w = cm.getColumnWidth(i);
53407 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53408 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53410 this.updateSplitters();
53413 generateRules : function(cm){
53414 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53415 Roo.util.CSS.removeStyleSheet(rulesId);
53416 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53417 var cid = cm.getColumnId(i);
53419 if(cm.config[i].align){
53420 align = 'text-align:'+cm.config[i].align+';';
53423 if(cm.isHidden(i)){
53424 hidden = 'display:none;';
53426 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53428 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53429 this.hdSelector, cid, " {\n", align, width, "}\n",
53430 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53431 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53433 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53436 updateSplitters : function(){
53437 var cm = this.cm, s = this.getSplitters();
53438 if(s){ // splitters not created yet
53439 var pos = 0, locked = true;
53440 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53441 if(cm.isHidden(i)) continue;
53442 var w = cm.getColumnWidth(i); // make sure it's a number
53443 if(!cm.isLocked(i) && locked){
53448 s[i].style.left = (pos-this.splitOffset) + "px";
53453 handleHiddenChange : function(colModel, colIndex, hidden){
53455 this.hideColumn(colIndex);
53457 this.unhideColumn(colIndex);
53461 hideColumn : function(colIndex){
53462 var cid = this.getColumnId(colIndex);
53463 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
53464 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
53466 this.updateHeaders();
53468 this.updateSplitters();
53472 unhideColumn : function(colIndex){
53473 var cid = this.getColumnId(colIndex);
53474 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
53475 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
53478 this.updateHeaders();
53480 this.updateSplitters();
53484 insertRows : function(dm, firstRow, lastRow, isUpdate){
53485 if(firstRow == 0 && lastRow == dm.getCount()-1){
53489 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
53491 var s = this.getScrollState();
53492 var markup = this.renderRows(firstRow, lastRow);
53493 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
53494 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
53495 this.restoreScroll(s);
53497 this.fireEvent("rowsinserted", this, firstRow, lastRow);
53498 this.syncRowHeights(firstRow, lastRow);
53499 this.stripeRows(firstRow);
53505 bufferRows : function(markup, target, index){
53506 var before = null, trows = target.rows, tbody = target.tBodies[0];
53507 if(index < trows.length){
53508 before = trows[index];
53510 var b = document.createElement("div");
53511 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
53512 var rows = b.firstChild.rows;
53513 for(var i = 0, len = rows.length; i < len; i++){
53515 tbody.insertBefore(rows[0], before);
53517 tbody.appendChild(rows[0]);
53524 deleteRows : function(dm, firstRow, lastRow){
53525 if(dm.getRowCount()<1){
53526 this.fireEvent("beforerefresh", this);
53527 this.mainBody.update("");
53528 this.lockedBody.update("");
53529 this.fireEvent("refresh", this);
53531 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
53532 var bt = this.getBodyTable();
53533 var tbody = bt.firstChild;
53534 var rows = bt.rows;
53535 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
53536 tbody.removeChild(rows[firstRow]);
53538 this.stripeRows(firstRow);
53539 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
53543 updateRows : function(dataSource, firstRow, lastRow){
53544 var s = this.getScrollState();
53546 this.restoreScroll(s);
53549 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
53553 this.updateHeaderSortState();
53556 getScrollState : function(){
53558 var sb = this.scroller.dom;
53559 return {left: sb.scrollLeft, top: sb.scrollTop};
53562 stripeRows : function(startRow){
53563 if(!this.grid.stripeRows || this.ds.getCount() < 1){
53566 startRow = startRow || 0;
53567 var rows = this.getBodyTable().rows;
53568 var lrows = this.getLockedTable().rows;
53569 var cls = ' x-grid-row-alt ';
53570 for(var i = startRow, len = rows.length; i < len; i++){
53571 var row = rows[i], lrow = lrows[i];
53572 var isAlt = ((i+1) % 2 == 0);
53573 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
53574 if(isAlt == hasAlt){
53578 row.className += " x-grid-row-alt";
53580 row.className = row.className.replace("x-grid-row-alt", "");
53583 lrow.className = row.className;
53588 restoreScroll : function(state){
53589 //Roo.log('GridView.restoreScroll');
53590 var sb = this.scroller.dom;
53591 sb.scrollLeft = state.left;
53592 sb.scrollTop = state.top;
53596 syncScroll : function(){
53597 //Roo.log('GridView.syncScroll');
53598 var sb = this.scroller.dom;
53599 var sh = this.mainHd.dom;
53600 var bs = this.mainBody.dom;
53601 var lv = this.lockedBody.dom;
53602 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
53603 lv.scrollTop = bs.scrollTop = sb.scrollTop;
53606 handleScroll : function(e){
53608 var sb = this.scroller.dom;
53609 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
53613 handleWheel : function(e){
53614 var d = e.getWheelDelta();
53615 this.scroller.dom.scrollTop -= d*22;
53616 // set this here to prevent jumpy scrolling on large tables
53617 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
53621 renderRows : function(startRow, endRow){
53622 // pull in all the crap needed to render rows
53623 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
53624 var colCount = cm.getColumnCount();
53626 if(ds.getCount() < 1){
53630 // build a map for all the columns
53632 for(var i = 0; i < colCount; i++){
53633 var name = cm.getDataIndex(i);
53635 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
53636 renderer : cm.getRenderer(i),
53637 id : cm.getColumnId(i),
53638 locked : cm.isLocked(i)
53642 startRow = startRow || 0;
53643 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
53645 // records to render
53646 var rs = ds.getRange(startRow, endRow);
53648 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
53651 // As much as I hate to duplicate code, this was branched because FireFox really hates
53652 // [].join("") on strings. The performance difference was substantial enough to
53653 // branch this function
53654 doRender : Roo.isGecko ?
53655 function(cs, rs, ds, startRow, colCount, stripe){
53656 var ts = this.templates, ct = ts.cell, rt = ts.row;
53658 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53660 var hasListener = this.grid.hasListener('rowclass');
53662 for(var j = 0, len = rs.length; j < len; j++){
53663 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
53664 for(var i = 0; i < colCount; i++){
53666 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53668 p.css = p.attr = "";
53669 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53670 if(p.value == undefined || p.value === "") p.value = " ";
53671 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53672 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53674 var markup = ct.apply(p);
53682 if(stripe && ((rowIndex+1) % 2 == 0)){
53683 alt.push("x-grid-row-alt")
53686 alt.push( " x-grid-dirty-row");
53689 if(this.getRowClass){
53690 alt.push(this.getRowClass(r, rowIndex));
53696 rowIndex : rowIndex,
53699 this.grid.fireEvent('rowclass', this, rowcfg);
53700 alt.push(rowcfg.rowClass);
53702 rp.alt = alt.join(" ");
53703 lbuf+= rt.apply(rp);
53705 buf+= rt.apply(rp);
53707 return [lbuf, buf];
53709 function(cs, rs, ds, startRow, colCount, stripe){
53710 var ts = this.templates, ct = ts.cell, rt = ts.row;
53712 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53713 var hasListener = this.grid.hasListener('rowclass');
53716 for(var j = 0, len = rs.length; j < len; j++){
53717 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
53718 for(var i = 0; i < colCount; i++){
53720 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53722 p.css = p.attr = "";
53723 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53724 if(p.value == undefined || p.value === "") p.value = " ";
53725 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53726 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53729 var markup = ct.apply(p);
53731 cb[cb.length] = markup;
53733 lcb[lcb.length] = markup;
53737 if(stripe && ((rowIndex+1) % 2 == 0)){
53738 alt.push( "x-grid-row-alt");
53741 alt.push(" x-grid-dirty-row");
53744 if(this.getRowClass){
53745 alt.push( this.getRowClass(r, rowIndex));
53751 rowIndex : rowIndex,
53754 this.grid.fireEvent('rowclass', this, rowcfg);
53755 alt.push(rowcfg.rowClass);
53757 rp.alt = alt.join(" ");
53758 rp.cells = lcb.join("");
53759 lbuf[lbuf.length] = rt.apply(rp);
53760 rp.cells = cb.join("");
53761 buf[buf.length] = rt.apply(rp);
53763 return [lbuf.join(""), buf.join("")];
53766 renderBody : function(){
53767 var markup = this.renderRows();
53768 var bt = this.templates.body;
53769 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
53773 * Refreshes the grid
53774 * @param {Boolean} headersToo
53776 refresh : function(headersToo){
53777 this.fireEvent("beforerefresh", this);
53778 this.grid.stopEditing();
53779 var result = this.renderBody();
53780 this.lockedBody.update(result[0]);
53781 this.mainBody.update(result[1]);
53782 if(headersToo === true){
53783 this.updateHeaders();
53784 this.updateColumns();
53785 this.updateSplitters();
53786 this.updateHeaderSortState();
53788 this.syncRowHeights();
53790 this.fireEvent("refresh", this);
53793 handleColumnMove : function(cm, oldIndex, newIndex){
53794 this.indexMap = null;
53795 var s = this.getScrollState();
53796 this.refresh(true);
53797 this.restoreScroll(s);
53798 this.afterMove(newIndex);
53801 afterMove : function(colIndex){
53802 if(this.enableMoveAnim && Roo.enableFx){
53803 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
53805 // if multisort - fix sortOrder, and reload..
53806 if (this.grid.dataSource.multiSort) {
53807 // the we can call sort again..
53808 var dm = this.grid.dataSource;
53809 var cm = this.grid.colModel;
53811 for(var i = 0; i < cm.config.length; i++ ) {
53813 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
53814 continue; // dont' bother, it's not in sort list or being set.
53817 so.push(cm.config[i].dataIndex);
53820 dm.load(dm.lastOptions);
53827 updateCell : function(dm, rowIndex, dataIndex){
53828 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
53829 if(typeof colIndex == "undefined"){ // not present in grid
53832 var cm = this.grid.colModel;
53833 var cell = this.getCell(rowIndex, colIndex);
53834 var cellText = this.getCellText(rowIndex, colIndex);
53837 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
53838 id : cm.getColumnId(colIndex),
53839 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
53841 var renderer = cm.getRenderer(colIndex);
53842 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
53843 if(typeof val == "undefined" || val === "") val = " ";
53844 cellText.innerHTML = val;
53845 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
53846 this.syncRowHeights(rowIndex, rowIndex);
53849 calcColumnWidth : function(colIndex, maxRowsToMeasure){
53851 if(this.grid.autoSizeHeaders){
53852 var h = this.getHeaderCellMeasure(colIndex);
53853 maxWidth = Math.max(maxWidth, h.scrollWidth);
53856 if(this.cm.isLocked(colIndex)){
53857 tb = this.getLockedTable();
53860 tb = this.getBodyTable();
53861 index = colIndex - this.cm.getLockedCount();
53864 var rows = tb.rows;
53865 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
53866 for(var i = 0; i < stopIndex; i++){
53867 var cell = rows[i].childNodes[index].firstChild;
53868 maxWidth = Math.max(maxWidth, cell.scrollWidth);
53871 return maxWidth + /*margin for error in IE*/ 5;
53874 * Autofit a column to its content.
53875 * @param {Number} colIndex
53876 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
53878 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
53879 if(this.cm.isHidden(colIndex)){
53880 return; // can't calc a hidden column
53883 var cid = this.cm.getColumnId(colIndex);
53884 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
53885 if(this.grid.autoSizeHeaders){
53886 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
53889 var newWidth = this.calcColumnWidth(colIndex);
53890 this.cm.setColumnWidth(colIndex,
53891 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
53892 if(!suppressEvent){
53893 this.grid.fireEvent("columnresize", colIndex, newWidth);
53898 * Autofits all columns to their content and then expands to fit any extra space in the grid
53900 autoSizeColumns : function(){
53901 var cm = this.grid.colModel;
53902 var colCount = cm.getColumnCount();
53903 for(var i = 0; i < colCount; i++){
53904 this.autoSizeColumn(i, true, true);
53906 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
53909 this.updateColumns();
53915 * Autofits all columns to the grid's width proportionate with their current size
53916 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
53918 fitColumns : function(reserveScrollSpace){
53919 var cm = this.grid.colModel;
53920 var colCount = cm.getColumnCount();
53924 for (i = 0; i < colCount; i++){
53925 if(!cm.isHidden(i) && !cm.isFixed(i)){
53926 w = cm.getColumnWidth(i);
53932 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
53933 if(reserveScrollSpace){
53936 var frac = (avail - cm.getTotalWidth())/width;
53937 while (cols.length){
53940 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
53942 this.updateColumns();
53946 onRowSelect : function(rowIndex){
53947 var row = this.getRowComposite(rowIndex);
53948 row.addClass("x-grid-row-selected");
53951 onRowDeselect : function(rowIndex){
53952 var row = this.getRowComposite(rowIndex);
53953 row.removeClass("x-grid-row-selected");
53956 onCellSelect : function(row, col){
53957 var cell = this.getCell(row, col);
53959 Roo.fly(cell).addClass("x-grid-cell-selected");
53963 onCellDeselect : function(row, col){
53964 var cell = this.getCell(row, col);
53966 Roo.fly(cell).removeClass("x-grid-cell-selected");
53970 updateHeaderSortState : function(){
53972 // sort state can be single { field: xxx, direction : yyy}
53973 // or { xxx=>ASC , yyy : DESC ..... }
53976 if (!this.ds.multiSort) {
53977 var state = this.ds.getSortState();
53981 mstate[state.field] = state.direction;
53982 // FIXME... - this is not used here.. but might be elsewhere..
53983 this.sortState = state;
53986 mstate = this.ds.sortToggle;
53988 //remove existing sort classes..
53990 var sc = this.sortClasses;
53991 var hds = this.el.select(this.headerSelector).removeClass(sc);
53993 for(var f in mstate) {
53995 var sortColumn = this.cm.findColumnIndex(f);
53997 if(sortColumn != -1){
53998 var sortDir = mstate[f];
53999 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54008 handleHeaderClick : function(g, index,e){
54010 Roo.log("header click");
54013 // touch events on header are handled by context
54014 this.handleHdCtx(g,index,e);
54019 if(this.headersDisabled){
54022 var dm = g.dataSource, cm = g.colModel;
54023 if(!cm.isSortable(index)){
54028 if (dm.multiSort) {
54029 // update the sortOrder
54031 for(var i = 0; i < cm.config.length; i++ ) {
54033 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54034 continue; // dont' bother, it's not in sort list or being set.
54037 so.push(cm.config[i].dataIndex);
54043 dm.sort(cm.getDataIndex(index));
54047 destroy : function(){
54049 this.colMenu.removeAll();
54050 Roo.menu.MenuMgr.unregister(this.colMenu);
54051 this.colMenu.getEl().remove();
54052 delete this.colMenu;
54055 this.hmenu.removeAll();
54056 Roo.menu.MenuMgr.unregister(this.hmenu);
54057 this.hmenu.getEl().remove();
54060 if(this.grid.enableColumnMove){
54061 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54063 for(var dd in dds){
54064 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54065 var elid = dds[dd].dragElId;
54067 Roo.get(elid).remove();
54068 } else if(dds[dd].config.isTarget){
54069 dds[dd].proxyTop.remove();
54070 dds[dd].proxyBottom.remove();
54073 if(Roo.dd.DDM.locationCache[dd]){
54074 delete Roo.dd.DDM.locationCache[dd];
54077 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54080 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54081 this.bind(null, null);
54082 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54085 handleLockChange : function(){
54086 this.refresh(true);
54089 onDenyColumnLock : function(){
54093 onDenyColumnHide : function(){
54097 handleHdMenuClick : function(item){
54098 var index = this.hdCtxIndex;
54099 var cm = this.cm, ds = this.ds;
54102 ds.sort(cm.getDataIndex(index), "ASC");
54105 ds.sort(cm.getDataIndex(index), "DESC");
54108 var lc = cm.getLockedCount();
54109 if(cm.getColumnCount(true) <= lc+1){
54110 this.onDenyColumnLock();
54114 cm.setLocked(index, true, true);
54115 cm.moveColumn(index, lc);
54116 this.grid.fireEvent("columnmove", index, lc);
54118 cm.setLocked(index, true);
54122 var lc = cm.getLockedCount();
54123 if((lc-1) != index){
54124 cm.setLocked(index, false, true);
54125 cm.moveColumn(index, lc-1);
54126 this.grid.fireEvent("columnmove", index, lc-1);
54128 cm.setLocked(index, false);
54131 case 'wider': // used to expand cols on touch..
54133 var cw = cm.getColumnWidth(index);
54134 cw += (item.id == 'wider' ? 1 : -1) * 50;
54135 cw = Math.max(0, cw);
54136 cw = Math.min(cw,4000);
54137 cm.setColumnWidth(index, cw);
54141 index = cm.getIndexById(item.id.substr(4));
54143 if(item.checked && cm.getColumnCount(true) <= 1){
54144 this.onDenyColumnHide();
54147 cm.setHidden(index, item.checked);
54153 beforeColMenuShow : function(){
54154 var cm = this.cm, colCount = cm.getColumnCount();
54155 this.colMenu.removeAll();
54156 for(var i = 0; i < colCount; i++){
54157 this.colMenu.add(new Roo.menu.CheckItem({
54158 id: "col-"+cm.getColumnId(i),
54159 text: cm.getColumnHeader(i),
54160 checked: !cm.isHidden(i),
54166 handleHdCtx : function(g, index, e){
54168 var hd = this.getHeaderCell(index);
54169 this.hdCtxIndex = index;
54170 var ms = this.hmenu.items, cm = this.cm;
54171 ms.get("asc").setDisabled(!cm.isSortable(index));
54172 ms.get("desc").setDisabled(!cm.isSortable(index));
54173 if(this.grid.enableColLock !== false){
54174 ms.get("lock").setDisabled(cm.isLocked(index));
54175 ms.get("unlock").setDisabled(!cm.isLocked(index));
54177 this.hmenu.show(hd, "tl-bl");
54180 handleHdOver : function(e){
54181 var hd = this.findHeaderCell(e.getTarget());
54182 if(hd && !this.headersDisabled){
54183 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54184 this.fly(hd).addClass("x-grid-hd-over");
54189 handleHdOut : function(e){
54190 var hd = this.findHeaderCell(e.getTarget());
54192 this.fly(hd).removeClass("x-grid-hd-over");
54196 handleSplitDblClick : function(e, t){
54197 var i = this.getCellIndex(t);
54198 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54199 this.autoSizeColumn(i, true);
54204 render : function(){
54207 var colCount = cm.getColumnCount();
54209 if(this.grid.monitorWindowResize === true){
54210 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54212 var header = this.renderHeaders();
54213 var body = this.templates.body.apply({rows:""});
54214 var html = this.templates.master.apply({
54217 lockedHeader: header[0],
54221 //this.updateColumns();
54223 this.grid.getGridEl().dom.innerHTML = html;
54225 this.initElements();
54227 // a kludge to fix the random scolling effect in webkit
54228 this.el.on("scroll", function() {
54229 this.el.dom.scrollTop=0; // hopefully not recursive..
54232 this.scroller.on("scroll", this.handleScroll, this);
54233 this.lockedBody.on("mousewheel", this.handleWheel, this);
54234 this.mainBody.on("mousewheel", this.handleWheel, this);
54236 this.mainHd.on("mouseover", this.handleHdOver, this);
54237 this.mainHd.on("mouseout", this.handleHdOut, this);
54238 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54239 {delegate: "."+this.splitClass});
54241 this.lockedHd.on("mouseover", this.handleHdOver, this);
54242 this.lockedHd.on("mouseout", this.handleHdOut, this);
54243 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54244 {delegate: "."+this.splitClass});
54246 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54247 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54250 this.updateSplitters();
54252 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54253 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54254 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54257 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54258 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54260 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54261 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54263 if(this.grid.enableColLock !== false){
54264 this.hmenu.add('-',
54265 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54266 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54270 this.hmenu.add('-',
54271 {id:"wider", text: this.columnsWiderText},
54272 {id:"narrow", text: this.columnsNarrowText }
54278 if(this.grid.enableColumnHide !== false){
54280 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54281 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54282 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54284 this.hmenu.add('-',
54285 {id:"columns", text: this.columnsText, menu: this.colMenu}
54288 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54290 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54293 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54294 this.dd = new Roo.grid.GridDragZone(this.grid, {
54295 ddGroup : this.grid.ddGroup || 'GridDD'
54301 for(var i = 0; i < colCount; i++){
54302 if(cm.isHidden(i)){
54303 this.hideColumn(i);
54305 if(cm.config[i].align){
54306 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54307 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54311 this.updateHeaderSortState();
54313 this.beforeInitialResize();
54316 // two part rendering gives faster view to the user
54317 this.renderPhase2.defer(1, this);
54320 renderPhase2 : function(){
54321 // render the rows now
54323 if(this.grid.autoSizeColumns){
54324 this.autoSizeColumns();
54328 beforeInitialResize : function(){
54332 onColumnSplitterMoved : function(i, w){
54333 this.userResized = true;
54334 var cm = this.grid.colModel;
54335 cm.setColumnWidth(i, w, true);
54336 var cid = cm.getColumnId(i);
54337 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54338 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54339 this.updateSplitters();
54341 this.grid.fireEvent("columnresize", i, w);
54344 syncRowHeights : function(startIndex, endIndex){
54345 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54346 startIndex = startIndex || 0;
54347 var mrows = this.getBodyTable().rows;
54348 var lrows = this.getLockedTable().rows;
54349 var len = mrows.length-1;
54350 endIndex = Math.min(endIndex || len, len);
54351 for(var i = startIndex; i <= endIndex; i++){
54352 var m = mrows[i], l = lrows[i];
54353 var h = Math.max(m.offsetHeight, l.offsetHeight);
54354 m.style.height = l.style.height = h + "px";
54359 layout : function(initialRender, is2ndPass){
54361 var auto = g.autoHeight;
54362 var scrollOffset = 16;
54363 var c = g.getGridEl(), cm = this.cm,
54364 expandCol = g.autoExpandColumn,
54366 //c.beginMeasure();
54368 if(!c.dom.offsetWidth){ // display:none?
54370 this.lockedWrap.show();
54371 this.mainWrap.show();
54376 var hasLock = this.cm.isLocked(0);
54378 var tbh = this.headerPanel.getHeight();
54379 var bbh = this.footerPanel.getHeight();
54382 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54383 var newHeight = ch + c.getBorderWidth("tb");
54385 newHeight = Math.min(g.maxHeight, newHeight);
54387 c.setHeight(newHeight);
54391 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54394 var s = this.scroller;
54396 var csize = c.getSize(true);
54398 this.el.setSize(csize.width, csize.height);
54400 this.headerPanel.setWidth(csize.width);
54401 this.footerPanel.setWidth(csize.width);
54403 var hdHeight = this.mainHd.getHeight();
54404 var vw = csize.width;
54405 var vh = csize.height - (tbh + bbh);
54409 var bt = this.getBodyTable();
54410 var ltWidth = hasLock ?
54411 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54413 var scrollHeight = bt.offsetHeight;
54414 var scrollWidth = ltWidth + bt.offsetWidth;
54415 var vscroll = false, hscroll = false;
54417 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54419 var lw = this.lockedWrap, mw = this.mainWrap;
54420 var lb = this.lockedBody, mb = this.mainBody;
54422 setTimeout(function(){
54423 var t = s.dom.offsetTop;
54424 var w = s.dom.clientWidth,
54425 h = s.dom.clientHeight;
54428 lw.setSize(ltWidth, h);
54430 mw.setLeftTop(ltWidth, t);
54431 mw.setSize(w-ltWidth, h);
54433 lb.setHeight(h-hdHeight);
54434 mb.setHeight(h-hdHeight);
54436 if(is2ndPass !== true && !gv.userResized && expandCol){
54437 // high speed resize without full column calculation
54439 var ci = cm.getIndexById(expandCol);
54441 ci = cm.findColumnIndex(expandCol);
54443 ci = Math.max(0, ci); // make sure it's got at least the first col.
54444 var expandId = cm.getColumnId(ci);
54445 var tw = cm.getTotalWidth(false);
54446 var currentWidth = cm.getColumnWidth(ci);
54447 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54448 if(currentWidth != cw){
54449 cm.setColumnWidth(ci, cw, true);
54450 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54451 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54452 gv.updateSplitters();
54453 gv.layout(false, true);
54465 onWindowResize : function(){
54466 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
54472 appendFooter : function(parentEl){
54476 sortAscText : "Sort Ascending",
54477 sortDescText : "Sort Descending",
54478 lockText : "Lock Column",
54479 unlockText : "Unlock Column",
54480 columnsText : "Columns",
54482 columnsWiderText : "Wider",
54483 columnsNarrowText : "Thinner"
54487 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
54488 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
54489 this.proxy.el.addClass('x-grid3-col-dd');
54492 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
54493 handleMouseDown : function(e){
54497 callHandleMouseDown : function(e){
54498 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
54503 * Ext JS Library 1.1.1
54504 * Copyright(c) 2006-2007, Ext JS, LLC.
54506 * Originally Released Under LGPL - original licence link has changed is not relivant.
54509 * <script type="text/javascript">
54513 // This is a support class used internally by the Grid components
54514 Roo.grid.SplitDragZone = function(grid, hd, hd2){
54516 this.view = grid.getView();
54517 this.proxy = this.view.resizeProxy;
54518 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
54519 "gridSplitters" + this.grid.getGridEl().id, {
54520 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
54522 this.setHandleElId(Roo.id(hd));
54523 this.setOuterHandleElId(Roo.id(hd2));
54524 this.scroll = false;
54526 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
54527 fly: Roo.Element.fly,
54529 b4StartDrag : function(x, y){
54530 this.view.headersDisabled = true;
54531 this.proxy.setHeight(this.view.mainWrap.getHeight());
54532 var w = this.cm.getColumnWidth(this.cellIndex);
54533 var minw = Math.max(w-this.grid.minColumnWidth, 0);
54534 this.resetConstraints();
54535 this.setXConstraint(minw, 1000);
54536 this.setYConstraint(0, 0);
54537 this.minX = x - minw;
54538 this.maxX = x + 1000;
54540 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
54544 handleMouseDown : function(e){
54545 ev = Roo.EventObject.setEvent(e);
54546 var t = this.fly(ev.getTarget());
54547 if(t.hasClass("x-grid-split")){
54548 this.cellIndex = this.view.getCellIndex(t.dom);
54549 this.split = t.dom;
54550 this.cm = this.grid.colModel;
54551 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
54552 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
54557 endDrag : function(e){
54558 this.view.headersDisabled = false;
54559 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
54560 var diff = endX - this.startPos;
54561 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
54564 autoOffset : function(){
54565 this.setDelta(0,0);
54569 * Ext JS Library 1.1.1
54570 * Copyright(c) 2006-2007, Ext JS, LLC.
54572 * Originally Released Under LGPL - original licence link has changed is not relivant.
54575 * <script type="text/javascript">
54579 // This is a support class used internally by the Grid components
54580 Roo.grid.GridDragZone = function(grid, config){
54581 this.view = grid.getView();
54582 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
54583 if(this.view.lockedBody){
54584 this.setHandleElId(Roo.id(this.view.mainBody.dom));
54585 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
54587 this.scroll = false;
54589 this.ddel = document.createElement('div');
54590 this.ddel.className = 'x-grid-dd-wrap';
54593 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
54594 ddGroup : "GridDD",
54596 getDragData : function(e){
54597 var t = Roo.lib.Event.getTarget(e);
54598 var rowIndex = this.view.findRowIndex(t);
54599 var sm = this.grid.selModel;
54601 //Roo.log(rowIndex);
54603 if (sm.getSelectedCell) {
54604 // cell selection..
54605 if (!sm.getSelectedCell()) {
54608 if (rowIndex != sm.getSelectedCell()[0]) {
54614 if(rowIndex !== false){
54619 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
54621 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
54624 if (e.hasModifier()){
54625 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
54628 Roo.log("getDragData");
54633 rowIndex: rowIndex,
54634 selections:sm.getSelections ? sm.getSelections() : (
54635 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
54642 onInitDrag : function(e){
54643 var data = this.dragData;
54644 this.ddel.innerHTML = this.grid.getDragDropText();
54645 this.proxy.update(this.ddel);
54646 // fire start drag?
54649 afterRepair : function(){
54650 this.dragging = false;
54653 getRepairXY : function(e, data){
54657 onEndDrag : function(data, e){
54661 onValidDrop : function(dd, e, id){
54666 beforeInvalidDrop : function(e, id){
54671 * Ext JS Library 1.1.1
54672 * Copyright(c) 2006-2007, Ext JS, LLC.
54674 * Originally Released Under LGPL - original licence link has changed is not relivant.
54677 * <script type="text/javascript">
54682 * @class Roo.grid.ColumnModel
54683 * @extends Roo.util.Observable
54684 * This is the default implementation of a ColumnModel used by the Grid. It defines
54685 * the columns in the grid.
54688 var colModel = new Roo.grid.ColumnModel([
54689 {header: "Ticker", width: 60, sortable: true, locked: true},
54690 {header: "Company Name", width: 150, sortable: true},
54691 {header: "Market Cap.", width: 100, sortable: true},
54692 {header: "$ Sales", width: 100, sortable: true, renderer: money},
54693 {header: "Employees", width: 100, sortable: true, resizable: false}
54698 * The config options listed for this class are options which may appear in each
54699 * individual column definition.
54700 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
54702 * @param {Object} config An Array of column config objects. See this class's
54703 * config objects for details.
54705 Roo.grid.ColumnModel = function(config){
54707 * The config passed into the constructor
54709 this.config = config;
54712 // if no id, create one
54713 // if the column does not have a dataIndex mapping,
54714 // map it to the order it is in the config
54715 for(var i = 0, len = config.length; i < len; i++){
54717 if(typeof c.dataIndex == "undefined"){
54720 if(typeof c.renderer == "string"){
54721 c.renderer = Roo.util.Format[c.renderer];
54723 if(typeof c.id == "undefined"){
54726 if(c.editor && c.editor.xtype){
54727 c.editor = Roo.factory(c.editor, Roo.grid);
54729 if(c.editor && c.editor.isFormField){
54730 c.editor = new Roo.grid.GridEditor(c.editor);
54732 this.lookup[c.id] = c;
54736 * The width of columns which have no width specified (defaults to 100)
54739 this.defaultWidth = 100;
54742 * Default sortable of columns which have no sortable specified (defaults to false)
54745 this.defaultSortable = false;
54749 * @event widthchange
54750 * Fires when the width of a column changes.
54751 * @param {ColumnModel} this
54752 * @param {Number} columnIndex The column index
54753 * @param {Number} newWidth The new width
54755 "widthchange": true,
54757 * @event headerchange
54758 * Fires when the text of a header changes.
54759 * @param {ColumnModel} this
54760 * @param {Number} columnIndex The column index
54761 * @param {Number} newText The new header text
54763 "headerchange": true,
54765 * @event hiddenchange
54766 * Fires when a column is hidden or "unhidden".
54767 * @param {ColumnModel} this
54768 * @param {Number} columnIndex The column index
54769 * @param {Boolean} hidden true if hidden, false otherwise
54771 "hiddenchange": true,
54773 * @event columnmoved
54774 * Fires when a column is moved.
54775 * @param {ColumnModel} this
54776 * @param {Number} oldIndex
54777 * @param {Number} newIndex
54779 "columnmoved" : true,
54781 * @event columlockchange
54782 * Fires when a column's locked state is changed
54783 * @param {ColumnModel} this
54784 * @param {Number} colIndex
54785 * @param {Boolean} locked true if locked
54787 "columnlockchange" : true
54789 Roo.grid.ColumnModel.superclass.constructor.call(this);
54791 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
54793 * @cfg {String} header The header text to display in the Grid view.
54796 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
54797 * {@link Roo.data.Record} definition from which to draw the column's value. If not
54798 * specified, the column's index is used as an index into the Record's data Array.
54801 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
54802 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
54805 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
54806 * Defaults to the value of the {@link #defaultSortable} property.
54807 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
54810 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
54813 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
54816 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
54819 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
54822 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
54823 * given the cell's data value. See {@link #setRenderer}. If not specified, the
54824 * default renderer uses the raw data value.
54827 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
54830 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
54834 * Returns the id of the column at the specified index.
54835 * @param {Number} index The column index
54836 * @return {String} the id
54838 getColumnId : function(index){
54839 return this.config[index].id;
54843 * Returns the column for a specified id.
54844 * @param {String} id The column id
54845 * @return {Object} the column
54847 getColumnById : function(id){
54848 return this.lookup[id];
54853 * Returns the column for a specified dataIndex.
54854 * @param {String} dataIndex The column dataIndex
54855 * @return {Object|Boolean} the column or false if not found
54857 getColumnByDataIndex: function(dataIndex){
54858 var index = this.findColumnIndex(dataIndex);
54859 return index > -1 ? this.config[index] : false;
54863 * Returns the index for a specified column id.
54864 * @param {String} id The column id
54865 * @return {Number} the index, or -1 if not found
54867 getIndexById : function(id){
54868 for(var i = 0, len = this.config.length; i < len; i++){
54869 if(this.config[i].id == id){
54877 * Returns the index for a specified column dataIndex.
54878 * @param {String} dataIndex The column dataIndex
54879 * @return {Number} the index, or -1 if not found
54882 findColumnIndex : function(dataIndex){
54883 for(var i = 0, len = this.config.length; i < len; i++){
54884 if(this.config[i].dataIndex == dataIndex){
54892 moveColumn : function(oldIndex, newIndex){
54893 var c = this.config[oldIndex];
54894 this.config.splice(oldIndex, 1);
54895 this.config.splice(newIndex, 0, c);
54896 this.dataMap = null;
54897 this.fireEvent("columnmoved", this, oldIndex, newIndex);
54900 isLocked : function(colIndex){
54901 return this.config[colIndex].locked === true;
54904 setLocked : function(colIndex, value, suppressEvent){
54905 if(this.isLocked(colIndex) == value){
54908 this.config[colIndex].locked = value;
54909 if(!suppressEvent){
54910 this.fireEvent("columnlockchange", this, colIndex, value);
54914 getTotalLockedWidth : function(){
54915 var totalWidth = 0;
54916 for(var i = 0; i < this.config.length; i++){
54917 if(this.isLocked(i) && !this.isHidden(i)){
54918 this.totalWidth += this.getColumnWidth(i);
54924 getLockedCount : function(){
54925 for(var i = 0, len = this.config.length; i < len; i++){
54926 if(!this.isLocked(i)){
54933 * Returns the number of columns.
54936 getColumnCount : function(visibleOnly){
54937 if(visibleOnly === true){
54939 for(var i = 0, len = this.config.length; i < len; i++){
54940 if(!this.isHidden(i)){
54946 return this.config.length;
54950 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
54951 * @param {Function} fn
54952 * @param {Object} scope (optional)
54953 * @return {Array} result
54955 getColumnsBy : function(fn, scope){
54957 for(var i = 0, len = this.config.length; i < len; i++){
54958 var c = this.config[i];
54959 if(fn.call(scope||this, c, i) === true){
54967 * Returns true if the specified column is sortable.
54968 * @param {Number} col The column index
54969 * @return {Boolean}
54971 isSortable : function(col){
54972 if(typeof this.config[col].sortable == "undefined"){
54973 return this.defaultSortable;
54975 return this.config[col].sortable;
54979 * Returns the rendering (formatting) function defined for the column.
54980 * @param {Number} col The column index.
54981 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
54983 getRenderer : function(col){
54984 if(!this.config[col].renderer){
54985 return Roo.grid.ColumnModel.defaultRenderer;
54987 return this.config[col].renderer;
54991 * Sets the rendering (formatting) function for a column.
54992 * @param {Number} col The column index
54993 * @param {Function} fn The function to use to process the cell's raw data
54994 * to return HTML markup for the grid view. The render function is called with
54995 * the following parameters:<ul>
54996 * <li>Data value.</li>
54997 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
54998 * <li>css A CSS style string to apply to the table cell.</li>
54999 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55000 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55001 * <li>Row index</li>
55002 * <li>Column index</li>
55003 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55005 setRenderer : function(col, fn){
55006 this.config[col].renderer = fn;
55010 * Returns the width for the specified column.
55011 * @param {Number} col The column index
55014 getColumnWidth : function(col){
55015 return this.config[col].width * 1 || this.defaultWidth;
55019 * Sets the width for a column.
55020 * @param {Number} col The column index
55021 * @param {Number} width The new width
55023 setColumnWidth : function(col, width, suppressEvent){
55024 this.config[col].width = width;
55025 this.totalWidth = null;
55026 if(!suppressEvent){
55027 this.fireEvent("widthchange", this, col, width);
55032 * Returns the total width of all columns.
55033 * @param {Boolean} includeHidden True to include hidden column widths
55036 getTotalWidth : function(includeHidden){
55037 if(!this.totalWidth){
55038 this.totalWidth = 0;
55039 for(var i = 0, len = this.config.length; i < len; i++){
55040 if(includeHidden || !this.isHidden(i)){
55041 this.totalWidth += this.getColumnWidth(i);
55045 return this.totalWidth;
55049 * Returns the header for the specified column.
55050 * @param {Number} col The column index
55053 getColumnHeader : function(col){
55054 return this.config[col].header;
55058 * Sets the header for a column.
55059 * @param {Number} col The column index
55060 * @param {String} header The new header
55062 setColumnHeader : function(col, header){
55063 this.config[col].header = header;
55064 this.fireEvent("headerchange", this, col, header);
55068 * Returns the tooltip for the specified column.
55069 * @param {Number} col The column index
55072 getColumnTooltip : function(col){
55073 return this.config[col].tooltip;
55076 * Sets the tooltip for a column.
55077 * @param {Number} col The column index
55078 * @param {String} tooltip The new tooltip
55080 setColumnTooltip : function(col, tooltip){
55081 this.config[col].tooltip = tooltip;
55085 * Returns the dataIndex for the specified column.
55086 * @param {Number} col The column index
55089 getDataIndex : function(col){
55090 return this.config[col].dataIndex;
55094 * Sets the dataIndex for a column.
55095 * @param {Number} col The column index
55096 * @param {Number} dataIndex The new dataIndex
55098 setDataIndex : function(col, dataIndex){
55099 this.config[col].dataIndex = dataIndex;
55105 * Returns true if the cell is editable.
55106 * @param {Number} colIndex The column index
55107 * @param {Number} rowIndex The row index
55108 * @return {Boolean}
55110 isCellEditable : function(colIndex, rowIndex){
55111 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55115 * Returns the editor defined for the cell/column.
55116 * return false or null to disable editing.
55117 * @param {Number} colIndex The column index
55118 * @param {Number} rowIndex The row index
55121 getCellEditor : function(colIndex, rowIndex){
55122 return this.config[colIndex].editor;
55126 * Sets if a column is editable.
55127 * @param {Number} col The column index
55128 * @param {Boolean} editable True if the column is editable
55130 setEditable : function(col, editable){
55131 this.config[col].editable = editable;
55136 * Returns true if the column is hidden.
55137 * @param {Number} colIndex The column index
55138 * @return {Boolean}
55140 isHidden : function(colIndex){
55141 return this.config[colIndex].hidden;
55146 * Returns true if the column width cannot be changed
55148 isFixed : function(colIndex){
55149 return this.config[colIndex].fixed;
55153 * Returns true if the column can be resized
55154 * @return {Boolean}
55156 isResizable : function(colIndex){
55157 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55160 * Sets if a column is hidden.
55161 * @param {Number} colIndex The column index
55162 * @param {Boolean} hidden True if the column is hidden
55164 setHidden : function(colIndex, hidden){
55165 this.config[colIndex].hidden = hidden;
55166 this.totalWidth = null;
55167 this.fireEvent("hiddenchange", this, colIndex, hidden);
55171 * Sets the editor for a column.
55172 * @param {Number} col The column index
55173 * @param {Object} editor The editor object
55175 setEditor : function(col, editor){
55176 this.config[col].editor = editor;
55180 Roo.grid.ColumnModel.defaultRenderer = function(value){
55181 if(typeof value == "string" && value.length < 1){
55187 // Alias for backwards compatibility
55188 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55191 * Ext JS Library 1.1.1
55192 * Copyright(c) 2006-2007, Ext JS, LLC.
55194 * Originally Released Under LGPL - original licence link has changed is not relivant.
55197 * <script type="text/javascript">
55201 * @class Roo.grid.AbstractSelectionModel
55202 * @extends Roo.util.Observable
55203 * Abstract base class for grid SelectionModels. It provides the interface that should be
55204 * implemented by descendant classes. This class should not be directly instantiated.
55207 Roo.grid.AbstractSelectionModel = function(){
55208 this.locked = false;
55209 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55212 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55213 /** @ignore Called by the grid automatically. Do not call directly. */
55214 init : function(grid){
55220 * Locks the selections.
55223 this.locked = true;
55227 * Unlocks the selections.
55229 unlock : function(){
55230 this.locked = false;
55234 * Returns true if the selections are locked.
55235 * @return {Boolean}
55237 isLocked : function(){
55238 return this.locked;
55242 * Ext JS Library 1.1.1
55243 * Copyright(c) 2006-2007, Ext JS, LLC.
55245 * Originally Released Under LGPL - original licence link has changed is not relivant.
55248 * <script type="text/javascript">
55251 * @extends Roo.grid.AbstractSelectionModel
55252 * @class Roo.grid.RowSelectionModel
55253 * The default SelectionModel used by {@link Roo.grid.Grid}.
55254 * It supports multiple selections and keyboard selection/navigation.
55256 * @param {Object} config
55258 Roo.grid.RowSelectionModel = function(config){
55259 Roo.apply(this, config);
55260 this.selections = new Roo.util.MixedCollection(false, function(o){
55265 this.lastActive = false;
55269 * @event selectionchange
55270 * Fires when the selection changes
55271 * @param {SelectionModel} this
55273 "selectionchange" : true,
55275 * @event afterselectionchange
55276 * Fires after the selection changes (eg. by key press or clicking)
55277 * @param {SelectionModel} this
55279 "afterselectionchange" : true,
55281 * @event beforerowselect
55282 * Fires when a row is selected being selected, return false to cancel.
55283 * @param {SelectionModel} this
55284 * @param {Number} rowIndex The selected index
55285 * @param {Boolean} keepExisting False if other selections will be cleared
55287 "beforerowselect" : true,
55290 * Fires when a row is selected.
55291 * @param {SelectionModel} this
55292 * @param {Number} rowIndex The selected index
55293 * @param {Roo.data.Record} r The record
55295 "rowselect" : true,
55297 * @event rowdeselect
55298 * Fires when a row is deselected.
55299 * @param {SelectionModel} this
55300 * @param {Number} rowIndex The selected index
55302 "rowdeselect" : true
55304 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55305 this.locked = false;
55308 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55310 * @cfg {Boolean} singleSelect
55311 * True to allow selection of only one row at a time (defaults to false)
55313 singleSelect : false,
55316 initEvents : function(){
55318 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55319 this.grid.on("mousedown", this.handleMouseDown, this);
55320 }else{ // allow click to work like normal
55321 this.grid.on("rowclick", this.handleDragableRowClick, this);
55324 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55325 "up" : function(e){
55327 this.selectPrevious(e.shiftKey);
55328 }else if(this.last !== false && this.lastActive !== false){
55329 var last = this.last;
55330 this.selectRange(this.last, this.lastActive-1);
55331 this.grid.getView().focusRow(this.lastActive);
55332 if(last !== false){
55336 this.selectFirstRow();
55338 this.fireEvent("afterselectionchange", this);
55340 "down" : function(e){
55342 this.selectNext(e.shiftKey);
55343 }else if(this.last !== false && this.lastActive !== false){
55344 var last = this.last;
55345 this.selectRange(this.last, this.lastActive+1);
55346 this.grid.getView().focusRow(this.lastActive);
55347 if(last !== false){
55351 this.selectFirstRow();
55353 this.fireEvent("afterselectionchange", this);
55358 var view = this.grid.view;
55359 view.on("refresh", this.onRefresh, this);
55360 view.on("rowupdated", this.onRowUpdated, this);
55361 view.on("rowremoved", this.onRemove, this);
55365 onRefresh : function(){
55366 var ds = this.grid.dataSource, i, v = this.grid.view;
55367 var s = this.selections;
55368 s.each(function(r){
55369 if((i = ds.indexOfId(r.id)) != -1){
55378 onRemove : function(v, index, r){
55379 this.selections.remove(r);
55383 onRowUpdated : function(v, index, r){
55384 if(this.isSelected(r)){
55385 v.onRowSelect(index);
55391 * @param {Array} records The records to select
55392 * @param {Boolean} keepExisting (optional) True to keep existing selections
55394 selectRecords : function(records, keepExisting){
55396 this.clearSelections();
55398 var ds = this.grid.dataSource;
55399 for(var i = 0, len = records.length; i < len; i++){
55400 this.selectRow(ds.indexOf(records[i]), true);
55405 * Gets the number of selected rows.
55408 getCount : function(){
55409 return this.selections.length;
55413 * Selects the first row in the grid.
55415 selectFirstRow : function(){
55420 * Select the last row.
55421 * @param {Boolean} keepExisting (optional) True to keep existing selections
55423 selectLastRow : function(keepExisting){
55424 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55428 * Selects the row immediately following the last selected row.
55429 * @param {Boolean} keepExisting (optional) True to keep existing selections
55431 selectNext : function(keepExisting){
55432 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55433 this.selectRow(this.last+1, keepExisting);
55434 this.grid.getView().focusRow(this.last);
55439 * Selects the row that precedes the last selected row.
55440 * @param {Boolean} keepExisting (optional) True to keep existing selections
55442 selectPrevious : function(keepExisting){
55444 this.selectRow(this.last-1, keepExisting);
55445 this.grid.getView().focusRow(this.last);
55450 * Returns the selected records
55451 * @return {Array} Array of selected records
55453 getSelections : function(){
55454 return [].concat(this.selections.items);
55458 * Returns the first selected record.
55461 getSelected : function(){
55462 return this.selections.itemAt(0);
55467 * Clears all selections.
55469 clearSelections : function(fast){
55470 if(this.locked) return;
55472 var ds = this.grid.dataSource;
55473 var s = this.selections;
55474 s.each(function(r){
55475 this.deselectRow(ds.indexOfId(r.id));
55479 this.selections.clear();
55486 * Selects all rows.
55488 selectAll : function(){
55489 if(this.locked) return;
55490 this.selections.clear();
55491 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
55492 this.selectRow(i, true);
55497 * Returns True if there is a selection.
55498 * @return {Boolean}
55500 hasSelection : function(){
55501 return this.selections.length > 0;
55505 * Returns True if the specified row is selected.
55506 * @param {Number/Record} record The record or index of the record to check
55507 * @return {Boolean}
55509 isSelected : function(index){
55510 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
55511 return (r && this.selections.key(r.id) ? true : false);
55515 * Returns True if the specified record id is selected.
55516 * @param {String} id The id of record to check
55517 * @return {Boolean}
55519 isIdSelected : function(id){
55520 return (this.selections.key(id) ? true : false);
55524 handleMouseDown : function(e, t){
55525 var view = this.grid.getView(), rowIndex;
55526 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
55529 if(e.shiftKey && this.last !== false){
55530 var last = this.last;
55531 this.selectRange(last, rowIndex, e.ctrlKey);
55532 this.last = last; // reset the last
55533 view.focusRow(rowIndex);
55535 var isSelected = this.isSelected(rowIndex);
55536 if(e.button !== 0 && isSelected){
55537 view.focusRow(rowIndex);
55538 }else if(e.ctrlKey && isSelected){
55539 this.deselectRow(rowIndex);
55540 }else if(!isSelected){
55541 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
55542 view.focusRow(rowIndex);
55545 this.fireEvent("afterselectionchange", this);
55548 handleDragableRowClick : function(grid, rowIndex, e)
55550 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
55551 this.selectRow(rowIndex, false);
55552 grid.view.focusRow(rowIndex);
55553 this.fireEvent("afterselectionchange", this);
55558 * Selects multiple rows.
55559 * @param {Array} rows Array of the indexes of the row to select
55560 * @param {Boolean} keepExisting (optional) True to keep existing selections
55562 selectRows : function(rows, keepExisting){
55564 this.clearSelections();
55566 for(var i = 0, len = rows.length; i < len; i++){
55567 this.selectRow(rows[i], true);
55572 * Selects a range of rows. All rows in between startRow and endRow are also selected.
55573 * @param {Number} startRow The index of the first row in the range
55574 * @param {Number} endRow The index of the last row in the range
55575 * @param {Boolean} keepExisting (optional) True to retain existing selections
55577 selectRange : function(startRow, endRow, keepExisting){
55578 if(this.locked) return;
55580 this.clearSelections();
55582 if(startRow <= endRow){
55583 for(var i = startRow; i <= endRow; i++){
55584 this.selectRow(i, true);
55587 for(var i = startRow; i >= endRow; i--){
55588 this.selectRow(i, true);
55594 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
55595 * @param {Number} startRow The index of the first row in the range
55596 * @param {Number} endRow The index of the last row in the range
55598 deselectRange : function(startRow, endRow, preventViewNotify){
55599 if(this.locked) return;
55600 for(var i = startRow; i <= endRow; i++){
55601 this.deselectRow(i, preventViewNotify);
55607 * @param {Number} row The index of the row to select
55608 * @param {Boolean} keepExisting (optional) True to keep existing selections
55610 selectRow : function(index, keepExisting, preventViewNotify){
55611 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
55612 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
55613 if(!keepExisting || this.singleSelect){
55614 this.clearSelections();
55616 var r = this.grid.dataSource.getAt(index);
55617 this.selections.add(r);
55618 this.last = this.lastActive = index;
55619 if(!preventViewNotify){
55620 this.grid.getView().onRowSelect(index);
55622 this.fireEvent("rowselect", this, index, r);
55623 this.fireEvent("selectionchange", this);
55629 * @param {Number} row The index of the row to deselect
55631 deselectRow : function(index, preventViewNotify){
55632 if(this.locked) return;
55633 if(this.last == index){
55636 if(this.lastActive == index){
55637 this.lastActive = false;
55639 var r = this.grid.dataSource.getAt(index);
55640 this.selections.remove(r);
55641 if(!preventViewNotify){
55642 this.grid.getView().onRowDeselect(index);
55644 this.fireEvent("rowdeselect", this, index);
55645 this.fireEvent("selectionchange", this);
55649 restoreLast : function(){
55651 this.last = this._last;
55656 acceptsNav : function(row, col, cm){
55657 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55661 onEditorKey : function(field, e){
55662 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
55667 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55669 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55671 }else if(k == e.ENTER && !e.ctrlKey){
55675 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
55677 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
55679 }else if(k == e.ESC){
55683 g.startEditing(newCell[0], newCell[1]);
55688 * Ext JS Library 1.1.1
55689 * Copyright(c) 2006-2007, Ext JS, LLC.
55691 * Originally Released Under LGPL - original licence link has changed is not relivant.
55694 * <script type="text/javascript">
55697 * @class Roo.grid.CellSelectionModel
55698 * @extends Roo.grid.AbstractSelectionModel
55699 * This class provides the basic implementation for cell selection in a grid.
55701 * @param {Object} config The object containing the configuration of this model.
55702 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
55704 Roo.grid.CellSelectionModel = function(config){
55705 Roo.apply(this, config);
55707 this.selection = null;
55711 * @event beforerowselect
55712 * Fires before a cell is selected.
55713 * @param {SelectionModel} this
55714 * @param {Number} rowIndex The selected row index
55715 * @param {Number} colIndex The selected cell index
55717 "beforecellselect" : true,
55719 * @event cellselect
55720 * Fires when a cell is selected.
55721 * @param {SelectionModel} this
55722 * @param {Number} rowIndex The selected row index
55723 * @param {Number} colIndex The selected cell index
55725 "cellselect" : true,
55727 * @event selectionchange
55728 * Fires when the active selection changes.
55729 * @param {SelectionModel} this
55730 * @param {Object} selection null for no selection or an object (o) with two properties
55732 <li>o.record: the record object for the row the selection is in</li>
55733 <li>o.cell: An array of [rowIndex, columnIndex]</li>
55736 "selectionchange" : true,
55739 * Fires when the tab (or enter) was pressed on the last editable cell
55740 * You can use this to trigger add new row.
55741 * @param {SelectionModel} this
55745 * @event beforeeditnext
55746 * Fires before the next editable sell is made active
55747 * You can use this to skip to another cell or fire the tabend
55748 * if you set cell to false
55749 * @param {Object} eventdata object : { cell : [ row, col ] }
55751 "beforeeditnext" : true
55753 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
55756 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
55758 enter_is_tab: false,
55761 initEvents : function(){
55762 this.grid.on("mousedown", this.handleMouseDown, this);
55763 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
55764 var view = this.grid.view;
55765 view.on("refresh", this.onViewChange, this);
55766 view.on("rowupdated", this.onRowUpdated, this);
55767 view.on("beforerowremoved", this.clearSelections, this);
55768 view.on("beforerowsinserted", this.clearSelections, this);
55769 if(this.grid.isEditor){
55770 this.grid.on("beforeedit", this.beforeEdit, this);
55775 beforeEdit : function(e){
55776 this.select(e.row, e.column, false, true, e.record);
55780 onRowUpdated : function(v, index, r){
55781 if(this.selection && this.selection.record == r){
55782 v.onCellSelect(index, this.selection.cell[1]);
55787 onViewChange : function(){
55788 this.clearSelections(true);
55792 * Returns the currently selected cell,.
55793 * @return {Array} The selected cell (row, column) or null if none selected.
55795 getSelectedCell : function(){
55796 return this.selection ? this.selection.cell : null;
55800 * Clears all selections.
55801 * @param {Boolean} true to prevent the gridview from being notified about the change.
55803 clearSelections : function(preventNotify){
55804 var s = this.selection;
55806 if(preventNotify !== true){
55807 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
55809 this.selection = null;
55810 this.fireEvent("selectionchange", this, null);
55815 * Returns true if there is a selection.
55816 * @return {Boolean}
55818 hasSelection : function(){
55819 return this.selection ? true : false;
55823 handleMouseDown : function(e, t){
55824 var v = this.grid.getView();
55825 if(this.isLocked()){
55828 var row = v.findRowIndex(t);
55829 var cell = v.findCellIndex(t);
55830 if(row !== false && cell !== false){
55831 this.select(row, cell);
55837 * @param {Number} rowIndex
55838 * @param {Number} collIndex
55840 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
55841 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
55842 this.clearSelections();
55843 r = r || this.grid.dataSource.getAt(rowIndex);
55846 cell : [rowIndex, colIndex]
55848 if(!preventViewNotify){
55849 var v = this.grid.getView();
55850 v.onCellSelect(rowIndex, colIndex);
55851 if(preventFocus !== true){
55852 v.focusCell(rowIndex, colIndex);
55855 this.fireEvent("cellselect", this, rowIndex, colIndex);
55856 this.fireEvent("selectionchange", this, this.selection);
55861 isSelectable : function(rowIndex, colIndex, cm){
55862 return !cm.isHidden(colIndex);
55866 handleKeyDown : function(e){
55867 //Roo.log('Cell Sel Model handleKeyDown');
55868 if(!e.isNavKeyPress()){
55871 var g = this.grid, s = this.selection;
55874 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
55876 this.select(cell[0], cell[1]);
55881 var walk = function(row, col, step){
55882 return g.walkCells(row, col, step, sm.isSelectable, sm);
55884 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
55891 // handled by onEditorKey
55892 if (g.isEditor && g.editing) {
55896 newCell = walk(r, c-1, -1);
55898 newCell = walk(r, c+1, 1);
55903 newCell = walk(r+1, c, 1);
55907 newCell = walk(r-1, c, -1);
55911 newCell = walk(r, c+1, 1);
55915 newCell = walk(r, c-1, -1);
55920 if(g.isEditor && !g.editing){
55921 g.startEditing(r, c);
55930 this.select(newCell[0], newCell[1]);
55936 acceptsNav : function(row, col, cm){
55937 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55941 * @param {Number} field (not used) - as it's normally used as a listener
55942 * @param {Number} e - event - fake it by using
55944 * var e = Roo.EventObjectImpl.prototype;
55945 * e.keyCode = e.TAB
55949 onEditorKey : function(field, e){
55951 var k = e.getKey(),
55954 ed = g.activeEditor,
55956 ///Roo.log('onEditorKey' + k);
55959 if (this.enter_is_tab && k == e.ENTER) {
55965 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55967 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55973 } else if(k == e.ENTER && !e.ctrlKey){
55976 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55978 } else if(k == e.ESC){
55983 var ecall = { cell : newCell, forward : forward };
55984 this.fireEvent('beforeeditnext', ecall );
55985 newCell = ecall.cell;
55986 forward = ecall.forward;
55990 //Roo.log('next cell after edit');
55991 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
55992 } else if (forward) {
55993 // tabbed past last
55994 this.fireEvent.defer(100, this, ['tabend',this]);
55999 * Ext JS Library 1.1.1
56000 * Copyright(c) 2006-2007, Ext JS, LLC.
56002 * Originally Released Under LGPL - original licence link has changed is not relivant.
56005 * <script type="text/javascript">
56009 * @class Roo.grid.EditorGrid
56010 * @extends Roo.grid.Grid
56011 * Class for creating and editable grid.
56012 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56013 * The container MUST have some type of size defined for the grid to fill. The container will be
56014 * automatically set to position relative if it isn't already.
56015 * @param {Object} dataSource The data model to bind to
56016 * @param {Object} colModel The column model with info about this grid's columns
56018 Roo.grid.EditorGrid = function(container, config){
56019 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56020 this.getGridEl().addClass("xedit-grid");
56022 if(!this.selModel){
56023 this.selModel = new Roo.grid.CellSelectionModel();
56026 this.activeEditor = null;
56030 * @event beforeedit
56031 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56032 * <ul style="padding:5px;padding-left:16px;">
56033 * <li>grid - This grid</li>
56034 * <li>record - The record being edited</li>
56035 * <li>field - The field name being edited</li>
56036 * <li>value - The value for the field being edited.</li>
56037 * <li>row - The grid row index</li>
56038 * <li>column - The grid column index</li>
56039 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56041 * @param {Object} e An edit event (see above for description)
56043 "beforeedit" : true,
56046 * Fires after a cell is edited. <br />
56047 * <ul style="padding:5px;padding-left:16px;">
56048 * <li>grid - This grid</li>
56049 * <li>record - The record being edited</li>
56050 * <li>field - The field name being edited</li>
56051 * <li>value - The value being set</li>
56052 * <li>originalValue - The original value for the field, before the edit.</li>
56053 * <li>row - The grid row index</li>
56054 * <li>column - The grid column index</li>
56056 * @param {Object} e An edit event (see above for description)
56058 "afteredit" : true,
56060 * @event validateedit
56061 * Fires after a cell is edited, but before the value is set in the record.
56062 * You can use this to modify the value being set in the field, Return false
56063 * to cancel the change. The edit event object has the following properties <br />
56064 * <ul style="padding:5px;padding-left:16px;">
56065 * <li>editor - This editor</li>
56066 * <li>grid - This grid</li>
56067 * <li>record - The record being edited</li>
56068 * <li>field - The field name being edited</li>
56069 * <li>value - The value being set</li>
56070 * <li>originalValue - The original value for the field, before the edit.</li>
56071 * <li>row - The grid row index</li>
56072 * <li>column - The grid column index</li>
56073 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56075 * @param {Object} e An edit event (see above for description)
56077 "validateedit" : true
56079 this.on("bodyscroll", this.stopEditing, this);
56080 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56083 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56085 * @cfg {Number} clicksToEdit
56086 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56093 trackMouseOver: false, // causes very odd FF errors
56095 onCellDblClick : function(g, row, col){
56096 this.startEditing(row, col);
56099 onEditComplete : function(ed, value, startValue){
56100 this.editing = false;
56101 this.activeEditor = null;
56102 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56104 var field = this.colModel.getDataIndex(ed.col);
56109 originalValue: startValue,
56116 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56119 if(String(value) !== String(startValue)){
56121 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56122 r.set(field, e.value);
56123 // if we are dealing with a combo box..
56124 // then we also set the 'name' colum to be the displayField
56125 if (ed.field.displayField && ed.field.name) {
56126 r.set(ed.field.name, ed.field.el.dom.value);
56129 delete e.cancel; //?? why!!!
56130 this.fireEvent("afteredit", e);
56133 this.fireEvent("afteredit", e); // always fire it!
56135 this.view.focusCell(ed.row, ed.col);
56139 * Starts editing the specified for the specified row/column
56140 * @param {Number} rowIndex
56141 * @param {Number} colIndex
56143 startEditing : function(row, col){
56144 this.stopEditing();
56145 if(this.colModel.isCellEditable(col, row)){
56146 this.view.ensureVisible(row, col, true);
56148 var r = this.dataSource.getAt(row);
56149 var field = this.colModel.getDataIndex(col);
56150 var cell = Roo.get(this.view.getCell(row,col));
56155 value: r.data[field],
56160 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56161 this.editing = true;
56162 var ed = this.colModel.getCellEditor(col, row);
56168 ed.render(ed.parentEl || document.body);
56174 (function(){ // complex but required for focus issues in safari, ie and opera
56178 ed.on("complete", this.onEditComplete, this, {single: true});
56179 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56180 this.activeEditor = ed;
56181 var v = r.data[field];
56182 ed.startEdit(this.view.getCell(row, col), v);
56183 // combo's with 'displayField and name set
56184 if (ed.field.displayField && ed.field.name) {
56185 ed.field.el.dom.value = r.data[ed.field.name];
56189 }).defer(50, this);
56195 * Stops any active editing
56197 stopEditing : function(){
56198 if(this.activeEditor){
56199 this.activeEditor.completeEdit();
56201 this.activeEditor = null;
56205 * Called to get grid's drag proxy text, by default returns this.ddText.
56208 getDragDropText : function(){
56209 var count = this.selModel.getSelectedCell() ? 1 : 0;
56210 return String.format(this.ddText, count, count == 1 ? '' : 's');
56215 * Ext JS Library 1.1.1
56216 * Copyright(c) 2006-2007, Ext JS, LLC.
56218 * Originally Released Under LGPL - original licence link has changed is not relivant.
56221 * <script type="text/javascript">
56224 // private - not really -- you end up using it !
56225 // This is a support class used internally by the Grid components
56228 * @class Roo.grid.GridEditor
56229 * @extends Roo.Editor
56230 * Class for creating and editable grid elements.
56231 * @param {Object} config any settings (must include field)
56233 Roo.grid.GridEditor = function(field, config){
56234 if (!config && field.field) {
56236 field = Roo.factory(config.field, Roo.form);
56238 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56239 field.monitorTab = false;
56242 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56245 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56248 alignment: "tl-tl",
56251 cls: "x-small-editor x-grid-editor",
56256 * Ext JS Library 1.1.1
56257 * Copyright(c) 2006-2007, Ext JS, LLC.
56259 * Originally Released Under LGPL - original licence link has changed is not relivant.
56262 * <script type="text/javascript">
56267 Roo.grid.PropertyRecord = Roo.data.Record.create([
56268 {name:'name',type:'string'}, 'value'
56272 Roo.grid.PropertyStore = function(grid, source){
56274 this.store = new Roo.data.Store({
56275 recordType : Roo.grid.PropertyRecord
56277 this.store.on('update', this.onUpdate, this);
56279 this.setSource(source);
56281 Roo.grid.PropertyStore.superclass.constructor.call(this);
56286 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56287 setSource : function(o){
56289 this.store.removeAll();
56292 if(this.isEditableValue(o[k])){
56293 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56296 this.store.loadRecords({records: data}, {}, true);
56299 onUpdate : function(ds, record, type){
56300 if(type == Roo.data.Record.EDIT){
56301 var v = record.data['value'];
56302 var oldValue = record.modified['value'];
56303 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56304 this.source[record.id] = v;
56306 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56313 getProperty : function(row){
56314 return this.store.getAt(row);
56317 isEditableValue: function(val){
56318 if(val && val instanceof Date){
56320 }else if(typeof val == 'object' || typeof val == 'function'){
56326 setValue : function(prop, value){
56327 this.source[prop] = value;
56328 this.store.getById(prop).set('value', value);
56331 getSource : function(){
56332 return this.source;
56336 Roo.grid.PropertyColumnModel = function(grid, store){
56339 g.PropertyColumnModel.superclass.constructor.call(this, [
56340 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56341 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56343 this.store = store;
56344 this.bselect = Roo.DomHelper.append(document.body, {
56345 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56346 {tag: 'option', value: 'true', html: 'true'},
56347 {tag: 'option', value: 'false', html: 'false'}
56350 Roo.id(this.bselect);
56353 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56354 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56355 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56356 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56357 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56359 this.renderCellDelegate = this.renderCell.createDelegate(this);
56360 this.renderPropDelegate = this.renderProp.createDelegate(this);
56363 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56367 valueText : 'Value',
56369 dateFormat : 'm/j/Y',
56372 renderDate : function(dateVal){
56373 return dateVal.dateFormat(this.dateFormat);
56376 renderBool : function(bVal){
56377 return bVal ? 'true' : 'false';
56380 isCellEditable : function(colIndex, rowIndex){
56381 return colIndex == 1;
56384 getRenderer : function(col){
56386 this.renderCellDelegate : this.renderPropDelegate;
56389 renderProp : function(v){
56390 return this.getPropertyName(v);
56393 renderCell : function(val){
56395 if(val instanceof Date){
56396 rv = this.renderDate(val);
56397 }else if(typeof val == 'boolean'){
56398 rv = this.renderBool(val);
56400 return Roo.util.Format.htmlEncode(rv);
56403 getPropertyName : function(name){
56404 var pn = this.grid.propertyNames;
56405 return pn && pn[name] ? pn[name] : name;
56408 getCellEditor : function(colIndex, rowIndex){
56409 var p = this.store.getProperty(rowIndex);
56410 var n = p.data['name'], val = p.data['value'];
56412 if(typeof(this.grid.customEditors[n]) == 'string'){
56413 return this.editors[this.grid.customEditors[n]];
56415 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56416 return this.grid.customEditors[n];
56418 if(val instanceof Date){
56419 return this.editors['date'];
56420 }else if(typeof val == 'number'){
56421 return this.editors['number'];
56422 }else if(typeof val == 'boolean'){
56423 return this.editors['boolean'];
56425 return this.editors['string'];
56431 * @class Roo.grid.PropertyGrid
56432 * @extends Roo.grid.EditorGrid
56433 * This class represents the interface of a component based property grid control.
56434 * <br><br>Usage:<pre><code>
56435 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56443 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56444 * The container MUST have some type of size defined for the grid to fill. The container will be
56445 * automatically set to position relative if it isn't already.
56446 * @param {Object} config A config object that sets properties on this grid.
56448 Roo.grid.PropertyGrid = function(container, config){
56449 config = config || {};
56450 var store = new Roo.grid.PropertyStore(this);
56451 this.store = store;
56452 var cm = new Roo.grid.PropertyColumnModel(this, store);
56453 store.store.sort('name', 'ASC');
56454 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
56457 enableColLock:false,
56458 enableColumnMove:false,
56460 trackMouseOver: false,
56463 this.getGridEl().addClass('x-props-grid');
56464 this.lastEditRow = null;
56465 this.on('columnresize', this.onColumnResize, this);
56468 * @event beforepropertychange
56469 * Fires before a property changes (return false to stop?)
56470 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56471 * @param {String} id Record Id
56472 * @param {String} newval New Value
56473 * @param {String} oldval Old Value
56475 "beforepropertychange": true,
56477 * @event propertychange
56478 * Fires after a property changes
56479 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56480 * @param {String} id Record Id
56481 * @param {String} newval New Value
56482 * @param {String} oldval Old Value
56484 "propertychange": true
56486 this.customEditors = this.customEditors || {};
56488 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
56491 * @cfg {Object} customEditors map of colnames=> custom editors.
56492 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
56493 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
56494 * false disables editing of the field.
56498 * @cfg {Object} propertyNames map of property Names to their displayed value
56501 render : function(){
56502 Roo.grid.PropertyGrid.superclass.render.call(this);
56503 this.autoSize.defer(100, this);
56506 autoSize : function(){
56507 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
56509 this.view.fitColumns();
56513 onColumnResize : function(){
56514 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
56518 * Sets the data for the Grid
56519 * accepts a Key => Value object of all the elements avaiable.
56520 * @param {Object} data to appear in grid.
56522 setSource : function(source){
56523 this.store.setSource(source);
56527 * Gets all the data from the grid.
56528 * @return {Object} data data stored in grid
56530 getSource : function(){
56531 return this.store.getSource();
56540 * @class Roo.grid.Calendar
56541 * @extends Roo.util.Grid
56542 * This class extends the Grid to provide a calendar widget
56543 * <br><br>Usage:<pre><code>
56544 var grid = new Roo.grid.Calendar("my-container-id", {
56547 selModel: mySelectionModel,
56548 autoSizeColumns: true,
56549 monitorWindowResize: false,
56550 trackMouseOver: true
56551 eventstore : real data store..
56557 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56558 * The container MUST have some type of size defined for the grid to fill. The container will be
56559 * automatically set to position relative if it isn't already.
56560 * @param {Object} config A config object that sets properties on this grid.
56562 Roo.grid.Calendar = function(container, config){
56563 // initialize the container
56564 this.container = Roo.get(container);
56565 this.container.update("");
56566 this.container.setStyle("overflow", "hidden");
56567 this.container.addClass('x-grid-container');
56569 this.id = this.container.id;
56571 Roo.apply(this, config);
56572 // check and correct shorthanded configs
56576 for (var r = 0;r < 6;r++) {
56579 for (var c =0;c < 7;c++) {
56583 if (this.eventStore) {
56584 this.eventStore= Roo.factory(this.eventStore, Roo.data);
56585 this.eventStore.on('load',this.onLoad, this);
56586 this.eventStore.on('beforeload',this.clearEvents, this);
56590 this.dataSource = new Roo.data.Store({
56591 proxy: new Roo.data.MemoryProxy(rows),
56592 reader: new Roo.data.ArrayReader({}, [
56593 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
56596 this.dataSource.load();
56597 this.ds = this.dataSource;
56598 this.ds.xmodule = this.xmodule || false;
56601 var cellRender = function(v,x,r)
56603 return String.format(
56604 '<div class="fc-day fc-widget-content"><div>' +
56605 '<div class="fc-event-container"></div>' +
56606 '<div class="fc-day-number">{0}</div>'+
56608 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
56609 '</div></div>', v);
56614 this.colModel = new Roo.grid.ColumnModel( [
56616 xtype: 'ColumnModel',
56618 dataIndex : 'weekday0',
56620 renderer : cellRender
56623 xtype: 'ColumnModel',
56625 dataIndex : 'weekday1',
56627 renderer : cellRender
56630 xtype: 'ColumnModel',
56632 dataIndex : 'weekday2',
56633 header : 'Tuesday',
56634 renderer : cellRender
56637 xtype: 'ColumnModel',
56639 dataIndex : 'weekday3',
56640 header : 'Wednesday',
56641 renderer : cellRender
56644 xtype: 'ColumnModel',
56646 dataIndex : 'weekday4',
56647 header : 'Thursday',
56648 renderer : cellRender
56651 xtype: 'ColumnModel',
56653 dataIndex : 'weekday5',
56655 renderer : cellRender
56658 xtype: 'ColumnModel',
56660 dataIndex : 'weekday6',
56661 header : 'Saturday',
56662 renderer : cellRender
56665 this.cm = this.colModel;
56666 this.cm.xmodule = this.xmodule || false;
56670 //this.selModel = new Roo.grid.CellSelectionModel();
56671 //this.sm = this.selModel;
56672 //this.selModel.init(this);
56676 this.container.setWidth(this.width);
56680 this.container.setHeight(this.height);
56687 * The raw click event for the entire grid.
56688 * @param {Roo.EventObject} e
56693 * The raw dblclick event for the entire grid.
56694 * @param {Roo.EventObject} e
56698 * @event contextmenu
56699 * The raw contextmenu event for the entire grid.
56700 * @param {Roo.EventObject} e
56702 "contextmenu" : true,
56705 * The raw mousedown event for the entire grid.
56706 * @param {Roo.EventObject} e
56708 "mousedown" : true,
56711 * The raw mouseup event for the entire grid.
56712 * @param {Roo.EventObject} e
56717 * The raw mouseover event for the entire grid.
56718 * @param {Roo.EventObject} e
56720 "mouseover" : true,
56723 * The raw mouseout event for the entire grid.
56724 * @param {Roo.EventObject} e
56729 * The raw keypress event for the entire grid.
56730 * @param {Roo.EventObject} e
56735 * The raw keydown event for the entire grid.
56736 * @param {Roo.EventObject} e
56744 * Fires when a cell is clicked
56745 * @param {Grid} this
56746 * @param {Number} rowIndex
56747 * @param {Number} columnIndex
56748 * @param {Roo.EventObject} e
56750 "cellclick" : true,
56752 * @event celldblclick
56753 * Fires when a cell is double clicked
56754 * @param {Grid} this
56755 * @param {Number} rowIndex
56756 * @param {Number} columnIndex
56757 * @param {Roo.EventObject} e
56759 "celldblclick" : true,
56762 * Fires when a row is clicked
56763 * @param {Grid} this
56764 * @param {Number} rowIndex
56765 * @param {Roo.EventObject} e
56769 * @event rowdblclick
56770 * Fires when a row is double clicked
56771 * @param {Grid} this
56772 * @param {Number} rowIndex
56773 * @param {Roo.EventObject} e
56775 "rowdblclick" : true,
56777 * @event headerclick
56778 * Fires when a header is clicked
56779 * @param {Grid} this
56780 * @param {Number} columnIndex
56781 * @param {Roo.EventObject} e
56783 "headerclick" : true,
56785 * @event headerdblclick
56786 * Fires when a header cell is double clicked
56787 * @param {Grid} this
56788 * @param {Number} columnIndex
56789 * @param {Roo.EventObject} e
56791 "headerdblclick" : true,
56793 * @event rowcontextmenu
56794 * Fires when a row is right clicked
56795 * @param {Grid} this
56796 * @param {Number} rowIndex
56797 * @param {Roo.EventObject} e
56799 "rowcontextmenu" : true,
56801 * @event cellcontextmenu
56802 * Fires when a cell is right clicked
56803 * @param {Grid} this
56804 * @param {Number} rowIndex
56805 * @param {Number} cellIndex
56806 * @param {Roo.EventObject} e
56808 "cellcontextmenu" : true,
56810 * @event headercontextmenu
56811 * Fires when a header is right clicked
56812 * @param {Grid} this
56813 * @param {Number} columnIndex
56814 * @param {Roo.EventObject} e
56816 "headercontextmenu" : true,
56818 * @event bodyscroll
56819 * Fires when the body element is scrolled
56820 * @param {Number} scrollLeft
56821 * @param {Number} scrollTop
56823 "bodyscroll" : true,
56825 * @event columnresize
56826 * Fires when the user resizes a column
56827 * @param {Number} columnIndex
56828 * @param {Number} newSize
56830 "columnresize" : true,
56832 * @event columnmove
56833 * Fires when the user moves a column
56834 * @param {Number} oldIndex
56835 * @param {Number} newIndex
56837 "columnmove" : true,
56840 * Fires when row(s) start being dragged
56841 * @param {Grid} this
56842 * @param {Roo.GridDD} dd The drag drop object
56843 * @param {event} e The raw browser event
56845 "startdrag" : true,
56848 * Fires when a drag operation is complete
56849 * @param {Grid} this
56850 * @param {Roo.GridDD} dd The drag drop object
56851 * @param {event} e The raw browser event
56856 * Fires when dragged row(s) are dropped on a valid DD target
56857 * @param {Grid} this
56858 * @param {Roo.GridDD} dd The drag drop object
56859 * @param {String} targetId The target drag drop object
56860 * @param {event} e The raw browser event
56865 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
56866 * @param {Grid} this
56867 * @param {Roo.GridDD} dd The drag drop object
56868 * @param {String} targetId The target drag drop object
56869 * @param {event} e The raw browser event
56874 * Fires when the dragged row(s) first cross another DD target while being dragged
56875 * @param {Grid} this
56876 * @param {Roo.GridDD} dd The drag drop object
56877 * @param {String} targetId The target drag drop object
56878 * @param {event} e The raw browser event
56880 "dragenter" : true,
56883 * Fires when the dragged row(s) leave another DD target while being dragged
56884 * @param {Grid} this
56885 * @param {Roo.GridDD} dd The drag drop object
56886 * @param {String} targetId The target drag drop object
56887 * @param {event} e The raw browser event
56892 * Fires when a row is rendered, so you can change add a style to it.
56893 * @param {GridView} gridview The grid view
56894 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
56900 * Fires when the grid is rendered
56901 * @param {Grid} grid
56906 * Fires when a date is selected
56907 * @param {DatePicker} this
56908 * @param {Date} date The selected date
56912 * @event monthchange
56913 * Fires when the displayed month changes
56914 * @param {DatePicker} this
56915 * @param {Date} date The selected month
56917 'monthchange': true,
56919 * @event evententer
56920 * Fires when mouse over an event
56921 * @param {Calendar} this
56922 * @param {event} Event
56924 'evententer': true,
56926 * @event eventleave
56927 * Fires when the mouse leaves an
56928 * @param {Calendar} this
56931 'eventleave': true,
56933 * @event eventclick
56934 * Fires when the mouse click an
56935 * @param {Calendar} this
56938 'eventclick': true,
56940 * @event eventrender
56941 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
56942 * @param {Calendar} this
56943 * @param {data} data to be modified
56945 'eventrender': true
56949 Roo.grid.Grid.superclass.constructor.call(this);
56950 this.on('render', function() {
56951 this.view.el.addClass('x-grid-cal');
56953 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
56957 if (!Roo.grid.Calendar.style) {
56958 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
56961 '.x-grid-cal .x-grid-col' : {
56962 height: 'auto !important',
56963 'vertical-align': 'top'
56965 '.x-grid-cal .fc-event-hori' : {
56976 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
56978 * @cfg {Store} eventStore The store that loads events.
56983 activeDate : false,
56986 monitorWindowResize : false,
56989 resizeColumns : function() {
56990 var col = (this.view.el.getWidth() / 7) - 3;
56991 // loop through cols, and setWidth
56992 for(var i =0 ; i < 7 ; i++){
56993 this.cm.setColumnWidth(i, col);
56996 setDate :function(date) {
56998 Roo.log('setDate?');
57000 this.resizeColumns();
57001 var vd = this.activeDate;
57002 this.activeDate = date;
57003 // if(vd && this.el){
57004 // var t = date.getTime();
57005 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57006 // Roo.log('using add remove');
57008 // this.fireEvent('monthchange', this, date);
57010 // this.cells.removeClass("fc-state-highlight");
57011 // this.cells.each(function(c){
57012 // if(c.dateValue == t){
57013 // c.addClass("fc-state-highlight");
57014 // setTimeout(function(){
57015 // try{c.dom.firstChild.focus();}catch(e){}
57025 var days = date.getDaysInMonth();
57027 var firstOfMonth = date.getFirstDateOfMonth();
57028 var startingPos = firstOfMonth.getDay()-this.startDay;
57030 if(startingPos < this.startDay){
57034 var pm = date.add(Date.MONTH, -1);
57035 var prevStart = pm.getDaysInMonth()-startingPos;
57039 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57041 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57042 //this.cells.addClassOnOver('fc-state-hover');
57044 var cells = this.cells.elements;
57045 var textEls = this.textNodes;
57047 //Roo.each(cells, function(cell){
57048 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57051 days += startingPos;
57053 // convert everything to numbers so it's fast
57054 var day = 86400000;
57055 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57058 //Roo.log(prevStart);
57060 var today = new Date().clearTime().getTime();
57061 var sel = date.clearTime().getTime();
57062 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57063 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57064 var ddMatch = this.disabledDatesRE;
57065 var ddText = this.disabledDatesText;
57066 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57067 var ddaysText = this.disabledDaysText;
57068 var format = this.format;
57070 var setCellClass = function(cal, cell){
57072 //Roo.log('set Cell Class');
57074 var t = d.getTime();
57079 cell.dateValue = t;
57081 cell.className += " fc-today";
57082 cell.className += " fc-state-highlight";
57083 cell.title = cal.todayText;
57086 // disable highlight in other month..
57087 cell.className += " fc-state-highlight";
57092 //cell.className = " fc-state-disabled";
57093 cell.title = cal.minText;
57097 //cell.className = " fc-state-disabled";
57098 cell.title = cal.maxText;
57102 if(ddays.indexOf(d.getDay()) != -1){
57103 // cell.title = ddaysText;
57104 // cell.className = " fc-state-disabled";
57107 if(ddMatch && format){
57108 var fvalue = d.dateFormat(format);
57109 if(ddMatch.test(fvalue)){
57110 cell.title = ddText.replace("%0", fvalue);
57111 cell.className = " fc-state-disabled";
57115 if (!cell.initialClassName) {
57116 cell.initialClassName = cell.dom.className;
57119 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57124 for(; i < startingPos; i++) {
57125 cells[i].dayName = (++prevStart);
57126 Roo.log(textEls[i]);
57127 d.setDate(d.getDate()+1);
57129 //cells[i].className = "fc-past fc-other-month";
57130 setCellClass(this, cells[i]);
57135 for(; i < days; i++){
57136 intDay = i - startingPos + 1;
57137 cells[i].dayName = (intDay);
57138 d.setDate(d.getDate()+1);
57140 cells[i].className = ''; // "x-date-active";
57141 setCellClass(this, cells[i]);
57145 for(; i < 42; i++) {
57146 //textEls[i].innerHTML = (++extraDays);
57148 d.setDate(d.getDate()+1);
57149 cells[i].dayName = (++extraDays);
57150 cells[i].className = "fc-future fc-other-month";
57151 setCellClass(this, cells[i]);
57154 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57156 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57158 // this will cause all the cells to mis
57161 for (var r = 0;r < 6;r++) {
57162 for (var c =0;c < 7;c++) {
57163 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57167 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57168 for(i=0;i<cells.length;i++) {
57170 this.cells.elements[i].dayName = cells[i].dayName ;
57171 this.cells.elements[i].className = cells[i].className;
57172 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57173 this.cells.elements[i].title = cells[i].title ;
57174 this.cells.elements[i].dateValue = cells[i].dateValue ;
57180 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57181 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57183 ////if(totalRows != 6){
57184 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57185 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57188 this.fireEvent('monthchange', this, date);
57193 * Returns the grid's SelectionModel.
57194 * @return {SelectionModel}
57196 getSelectionModel : function(){
57197 if(!this.selModel){
57198 this.selModel = new Roo.grid.CellSelectionModel();
57200 return this.selModel;
57204 this.eventStore.load()
57210 findCell : function(dt) {
57211 dt = dt.clearTime().getTime();
57213 this.cells.each(function(c){
57214 //Roo.log("check " +c.dateValue + '?=' + dt);
57215 if(c.dateValue == dt){
57225 findCells : function(rec) {
57226 var s = rec.data.start_dt.clone().clearTime().getTime();
57228 var e= rec.data.end_dt.clone().clearTime().getTime();
57231 this.cells.each(function(c){
57232 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57234 if(c.dateValue > e){
57237 if(c.dateValue < s){
57246 findBestRow: function(cells)
57250 for (var i =0 ; i < cells.length;i++) {
57251 ret = Math.max(cells[i].rows || 0,ret);
57258 addItem : function(rec)
57260 // look for vertical location slot in
57261 var cells = this.findCells(rec);
57263 rec.row = this.findBestRow(cells);
57265 // work out the location.
57269 for(var i =0; i < cells.length; i++) {
57277 if (crow.start.getY() == cells[i].getY()) {
57279 crow.end = cells[i];
57295 for (var i = 0; i < cells.length;i++) {
57296 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57303 clearEvents: function() {
57305 if (!this.eventStore.getCount()) {
57308 // reset number of rows in cells.
57309 Roo.each(this.cells.elements, function(c){
57313 this.eventStore.each(function(e) {
57314 this.clearEvent(e);
57319 clearEvent : function(ev)
57322 Roo.each(ev.els, function(el) {
57323 el.un('mouseenter' ,this.onEventEnter, this);
57324 el.un('mouseleave' ,this.onEventLeave, this);
57332 renderEvent : function(ev,ctr) {
57334 ctr = this.view.el.select('.fc-event-container',true).first();
57338 this.clearEvent(ev);
57344 var cells = ev.cells;
57345 var rows = ev.rows;
57346 this.fireEvent('eventrender', this, ev);
57348 for(var i =0; i < rows.length; i++) {
57352 cls += ' fc-event-start';
57354 if ((i+1) == rows.length) {
57355 cls += ' fc-event-end';
57358 //Roo.log(ev.data);
57359 // how many rows should it span..
57360 var cg = this.eventTmpl.append(ctr,Roo.apply({
57363 }, ev.data) , true);
57366 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57367 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57368 cg.on('click', this.onEventClick, this, ev);
57372 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57373 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57376 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57377 cg.setWidth(ebox.right - sbox.x -2);
57381 renderEvents: function()
57383 // first make sure there is enough space..
57385 if (!this.eventTmpl) {
57386 this.eventTmpl = new Roo.Template(
57387 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57388 '<div class="fc-event-inner">' +
57389 '<span class="fc-event-time">{time}</span>' +
57390 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57392 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57400 this.cells.each(function(c) {
57401 //Roo.log(c.select('.fc-day-content div',true).first());
57402 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57405 var ctr = this.view.el.select('.fc-event-container',true).first();
57408 this.eventStore.each(function(ev){
57410 this.renderEvent(ev);
57414 this.view.layout();
57418 onEventEnter: function (e, el,event,d) {
57419 this.fireEvent('evententer', this, el, event);
57422 onEventLeave: function (e, el,event,d) {
57423 this.fireEvent('eventleave', this, el, event);
57426 onEventClick: function (e, el,event,d) {
57427 this.fireEvent('eventclick', this, el, event);
57430 onMonthChange: function () {
57434 onLoad: function () {
57436 //Roo.log('calendar onload');
57438 if(this.eventStore.getCount() > 0){
57442 this.eventStore.each(function(d){
57447 if (typeof(add.end_dt) == 'undefined') {
57448 Roo.log("Missing End time in calendar data: ");
57452 if (typeof(add.start_dt) == 'undefined') {
57453 Roo.log("Missing Start time in calendar data: ");
57457 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
57458 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
57459 add.id = add.id || d.id;
57460 add.title = add.title || '??';
57468 this.renderEvents();
57478 render : function ()
57482 if (!this.view.el.hasClass('course-timesheet')) {
57483 this.view.el.addClass('course-timesheet');
57485 if (this.tsStyle) {
57490 Roo.log(_this.grid.view.el.getWidth());
57493 this.tsStyle = Roo.util.CSS.createStyleSheet({
57494 '.course-timesheet .x-grid-row' : {
57497 '.x-grid-row td' : {
57498 'vertical-align' : 0
57500 '.course-edit-link' : {
57502 'text-overflow' : 'ellipsis',
57503 'overflow' : 'hidden',
57504 'white-space' : 'nowrap',
57505 'cursor' : 'pointer'
57510 '.de-act-sup-link' : {
57511 'color' : 'purple',
57512 'text-decoration' : 'line-through'
57516 'text-decoration' : 'line-through'
57518 '.course-timesheet .course-highlight' : {
57519 'border-top-style': 'dashed !important',
57520 'border-bottom-bottom': 'dashed !important'
57522 '.course-timesheet .course-item' : {
57523 'font-family' : 'tahoma, arial, helvetica',
57524 'font-size' : '11px',
57525 'overflow' : 'hidden',
57526 'padding-left' : '10px',
57527 'padding-right' : '10px',
57528 'padding-top' : '10px'
57536 monitorWindowResize : false,
57537 cellrenderer : function(v,x,r)
57542 xtype: 'CellSelectionModel',
57549 beforeload : function (_self, options)
57551 options.params = options.params || {};
57552 options.params._month = _this.monthField.getValue();
57553 options.params.limit = 9999;
57554 options.params['sort'] = 'when_dt';
57555 options.params['dir'] = 'ASC';
57556 this.proxy.loadResponse = this.loadResponse;
57558 //this.addColumns();
57560 load : function (_self, records, options)
57562 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
57563 // if you click on the translation.. you can edit it...
57564 var el = Roo.get(this);
57565 var id = el.dom.getAttribute('data-id');
57566 var d = el.dom.getAttribute('data-date');
57567 var t = el.dom.getAttribute('data-time');
57568 //var id = this.child('span').dom.textContent;
57571 Pman.Dialog.CourseCalendar.show({
57575 productitem_active : id ? 1 : 0
57577 _this.grid.ds.load({});
57582 _this.panel.fireEvent('resize', [ '', '' ]);
57585 loadResponse : function(o, success, response){
57586 // this is overridden on before load..
57588 Roo.log("our code?");
57589 //Roo.log(success);
57590 //Roo.log(response)
57591 delete this.activeRequest;
57593 this.fireEvent("loadexception", this, o, response);
57594 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57599 result = o.reader.read(response);
57601 Roo.log("load exception?");
57602 this.fireEvent("loadexception", this, o, response, e);
57603 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57606 Roo.log("ready...");
57607 // loop through result.records;
57608 // and set this.tdate[date] = [] << array of records..
57610 Roo.each(result.records, function(r){
57612 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
57613 _this.tdata[r.data.when_dt.format('j')] = [];
57615 _this.tdata[r.data.when_dt.format('j')].push(r.data);
57618 //Roo.log(_this.tdata);
57620 result.records = [];
57621 result.totalRecords = 6;
57623 // let's generate some duumy records for the rows.
57624 //var st = _this.dateField.getValue();
57626 // work out monday..
57627 //st = st.add(Date.DAY, -1 * st.format('w'));
57629 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57631 var firstOfMonth = date.getFirstDayOfMonth();
57632 var days = date.getDaysInMonth();
57634 var firstAdded = false;
57635 for (var i = 0; i < result.totalRecords ; i++) {
57636 //var d= st.add(Date.DAY, i);
57639 for(var w = 0 ; w < 7 ; w++){
57640 if(!firstAdded && firstOfMonth != w){
57647 var dd = (d > 0 && d < 10) ? "0"+d : d;
57648 row['weekday'+w] = String.format(
57649 '<span style="font-size: 16px;"><b>{0}</b></span>'+
57650 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
57652 date.format('Y-m-')+dd
57655 if(typeof(_this.tdata[d]) != 'undefined'){
57656 Roo.each(_this.tdata[d], function(r){
57660 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
57661 if(r.parent_id*1>0){
57662 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
57665 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
57666 deactive = 'de-act-link';
57669 row['weekday'+w] += String.format(
57670 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
57672 r.product_id_name, //1
57673 r.when_dt.format('h:ia'), //2
57683 // only do this if something added..
57685 result.records.push(_this.grid.dataSource.reader.newRow(row));
57689 // push it twice. (second one with an hour..
57693 this.fireEvent("load", this, o, o.request.arg);
57694 o.request.callback.call(o.request.scope, result, o.request.arg, true);
57696 sortInfo : {field: 'when_dt', direction : 'ASC' },
57698 xtype: 'HttpProxy',
57701 url : baseURL + '/Roo/Shop_course.php'
57704 xtype: 'JsonReader',
57721 'name': 'parent_id',
57725 'name': 'product_id',
57729 'name': 'productitem_id',
57747 click : function (_self, e)
57749 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57750 sd.setMonth(sd.getMonth()-1);
57751 _this.monthField.setValue(sd.format('Y-m-d'));
57752 _this.grid.ds.load({});
57758 xtype: 'Separator',
57762 xtype: 'MonthField',
57765 render : function (_self)
57767 _this.monthField = _self;
57768 // _this.monthField.set today
57770 select : function (combo, date)
57772 _this.grid.ds.load({});
57775 value : (function() { return new Date(); })()
57778 xtype: 'Separator',
57784 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
57794 click : function (_self, e)
57796 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57797 sd.setMonth(sd.getMonth()+1);
57798 _this.monthField.setValue(sd.format('Y-m-d'));
57799 _this.grid.ds.load({});
57812 * Ext JS Library 1.1.1
57813 * Copyright(c) 2006-2007, Ext JS, LLC.
57815 * Originally Released Under LGPL - original licence link has changed is not relivant.
57818 * <script type="text/javascript">
57822 * @class Roo.LoadMask
57823 * A simple utility class for generically masking elements while loading data. If the element being masked has
57824 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
57825 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
57826 * element's UpdateManager load indicator and will be destroyed after the initial load.
57828 * Create a new LoadMask
57829 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
57830 * @param {Object} config The config object
57832 Roo.LoadMask = function(el, config){
57833 this.el = Roo.get(el);
57834 Roo.apply(this, config);
57836 this.store.on('beforeload', this.onBeforeLoad, this);
57837 this.store.on('load', this.onLoad, this);
57838 this.store.on('loadexception', this.onLoadException, this);
57839 this.removeMask = false;
57841 var um = this.el.getUpdateManager();
57842 um.showLoadIndicator = false; // disable the default indicator
57843 um.on('beforeupdate', this.onBeforeLoad, this);
57844 um.on('update', this.onLoad, this);
57845 um.on('failure', this.onLoad, this);
57846 this.removeMask = true;
57850 Roo.LoadMask.prototype = {
57852 * @cfg {Boolean} removeMask
57853 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
57854 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
57857 * @cfg {String} msg
57858 * The text to display in a centered loading message box (defaults to 'Loading...')
57860 msg : 'Loading...',
57862 * @cfg {String} msgCls
57863 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
57865 msgCls : 'x-mask-loading',
57868 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
57874 * Disables the mask to prevent it from being displayed
57876 disable : function(){
57877 this.disabled = true;
57881 * Enables the mask so that it can be displayed
57883 enable : function(){
57884 this.disabled = false;
57887 onLoadException : function()
57889 Roo.log(arguments);
57891 if (typeof(arguments[3]) != 'undefined') {
57892 Roo.MessageBox.alert("Error loading",arguments[3]);
57896 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
57897 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
57906 this.el.unmask(this.removeMask);
57909 onLoad : function()
57911 this.el.unmask(this.removeMask);
57915 onBeforeLoad : function(){
57916 if(!this.disabled){
57917 this.el.mask(this.msg, this.msgCls);
57922 destroy : function(){
57924 this.store.un('beforeload', this.onBeforeLoad, this);
57925 this.store.un('load', this.onLoad, this);
57926 this.store.un('loadexception', this.onLoadException, this);
57928 var um = this.el.getUpdateManager();
57929 um.un('beforeupdate', this.onBeforeLoad, this);
57930 um.un('update', this.onLoad, this);
57931 um.un('failure', this.onLoad, this);
57936 * Ext JS Library 1.1.1
57937 * Copyright(c) 2006-2007, Ext JS, LLC.
57939 * Originally Released Under LGPL - original licence link has changed is not relivant.
57942 * <script type="text/javascript">
57947 * @class Roo.XTemplate
57948 * @extends Roo.Template
57949 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
57951 var t = new Roo.XTemplate(
57952 '<select name="{name}">',
57953 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
57957 // then append, applying the master template values
57960 * Supported features:
57965 {a_variable} - output encoded.
57966 {a_variable.format:("Y-m-d")} - call a method on the variable
57967 {a_variable:raw} - unencoded output
57968 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
57969 {a_variable:this.method_on_template(...)} - call a method on the template object.
57974 <tpl for="a_variable or condition.."></tpl>
57975 <tpl if="a_variable or condition"></tpl>
57976 <tpl exec="some javascript"></tpl>
57977 <tpl name="named_template"></tpl> (experimental)
57979 <tpl for="."></tpl> - just iterate the property..
57980 <tpl for=".."></tpl> - iterates with the parent (probably the template)
57984 Roo.XTemplate = function()
57986 Roo.XTemplate.superclass.constructor.apply(this, arguments);
57993 Roo.extend(Roo.XTemplate, Roo.Template, {
57996 * The various sub templates
58001 * basic tag replacing syntax
58004 * // you can fake an object call by doing this
58008 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58011 * compile the template
58013 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58016 compile: function()
58020 s = ['<tpl>', s, '</tpl>'].join('');
58022 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58023 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58024 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58025 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58026 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58031 while(true == !!(m = s.match(re))){
58032 var forMatch = m[0].match(nameRe),
58033 ifMatch = m[0].match(ifRe),
58034 execMatch = m[0].match(execRe),
58035 namedMatch = m[0].match(namedRe),
58040 name = forMatch && forMatch[1] ? forMatch[1] : '';
58043 // if - puts fn into test..
58044 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58046 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58051 // exec - calls a function... returns empty if true is returned.
58052 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58054 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58062 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58063 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58064 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58067 var uid = namedMatch ? namedMatch[1] : id;
58071 id: namedMatch ? namedMatch[1] : id,
58078 s = s.replace(m[0], '');
58080 s = s.replace(m[0], '{xtpl'+ id + '}');
58085 for(var i = tpls.length-1; i >= 0; --i){
58086 this.compileTpl(tpls[i]);
58087 this.tpls[tpls[i].id] = tpls[i];
58089 this.master = tpls[tpls.length-1];
58093 * same as applyTemplate, except it's done to one of the subTemplates
58094 * when using named templates, you can do:
58096 * var str = pl.applySubTemplate('your-name', values);
58099 * @param {Number} id of the template
58100 * @param {Object} values to apply to template
58101 * @param {Object} parent (normaly the instance of this object)
58103 applySubTemplate : function(id, values, parent)
58107 var t = this.tpls[id];
58111 if(t.test && !t.test.call(this, values, parent)){
58115 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58116 Roo.log(e.toString());
58122 if(t.exec && t.exec.call(this, values, parent)){
58126 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58127 Roo.log(e.toString());
58132 var vs = t.target ? t.target.call(this, values, parent) : values;
58133 parent = t.target ? values : parent;
58134 if(t.target && vs instanceof Array){
58136 for(var i = 0, len = vs.length; i < len; i++){
58137 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58139 return buf.join('');
58141 return t.compiled.call(this, vs, parent);
58143 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58144 Roo.log(e.toString());
58145 Roo.log(t.compiled);
58150 compileTpl : function(tpl)
58152 var fm = Roo.util.Format;
58153 var useF = this.disableFormats !== true;
58154 var sep = Roo.isGecko ? "+" : ",";
58155 var undef = function(str) {
58156 Roo.log("Property not found :" + str);
58160 var fn = function(m, name, format, args)
58162 //Roo.log(arguments);
58163 args = args ? args.replace(/\\'/g,"'") : args;
58164 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58165 if (typeof(format) == 'undefined') {
58166 format= 'htmlEncode';
58168 if (format == 'raw' ) {
58172 if(name.substr(0, 4) == 'xtpl'){
58173 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58176 // build an array of options to determine if value is undefined..
58178 // basically get 'xxxx.yyyy' then do
58179 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58180 // (function () { Roo.log("Property not found"); return ''; })() :
58185 Roo.each(name.split('.'), function(st) {
58186 lookfor += (lookfor.length ? '.': '') + st;
58187 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58190 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58193 if(format && useF){
58195 args = args ? ',' + args : "";
58197 if(format.substr(0, 5) != "this."){
58198 format = "fm." + format + '(';
58200 format = 'this.call("'+ format.substr(5) + '", ';
58204 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58208 // called with xxyx.yuu:(test,test)
58210 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58212 // raw.. - :raw modifier..
58213 return "'"+ sep + udef_st + name + ")"+sep+"'";
58217 // branched to use + in gecko and [].join() in others
58219 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58220 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58223 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58224 body.push(tpl.body.replace(/(\r\n|\n)/g,
58225 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58226 body.push("'].join('');};};");
58227 body = body.join('');
58230 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58232 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58238 applyTemplate : function(values){
58239 return this.master.compiled.call(this, values, {});
58240 //var s = this.subs;
58243 apply : function(){
58244 return this.applyTemplate.apply(this, arguments);
58249 Roo.XTemplate.from = function(el){
58250 el = Roo.getDom(el);
58251 return new Roo.XTemplate(el.value || el.innerHTML);