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", "Roo.app", "Roo.ux");
652 * Ext JS Library 1.1.1
653 * Copyright(c) 2006-2007, Ext JS, LLC.
655 * Originally Released Under LGPL - original licence link has changed is not relivant.
658 * <script type="text/javascript">
662 // wrappedn so fnCleanup is not in global scope...
664 function fnCleanUp() {
665 var p = Function.prototype;
666 delete p.createSequence;
668 delete p.createDelegate;
669 delete p.createCallback;
670 delete p.createInterceptor;
672 window.detachEvent("onunload", fnCleanUp);
674 window.attachEvent("onunload", fnCleanUp);
681 * These functions are available on every Function object (any JavaScript function).
683 Roo.apply(Function.prototype, {
685 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
686 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
687 * Will create a function that is bound to those 2 args.
688 * @return {Function} The new function
690 createCallback : function(/*args...*/){
691 // make args available, in function below
692 var args = arguments;
695 return method.apply(window, args);
700 * Creates a delegate (callback) that sets the scope to obj.
701 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
702 * Will create a function that is automatically scoped to this.
703 * @param {Object} obj (optional) The object for which the scope is set
704 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
705 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
706 * if a number the args are inserted at the specified position
707 * @return {Function} The new function
709 createDelegate : function(obj, args, appendArgs){
712 var callArgs = args || arguments;
713 if(appendArgs === true){
714 callArgs = Array.prototype.slice.call(arguments, 0);
715 callArgs = callArgs.concat(args);
716 }else if(typeof appendArgs == "number"){
717 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
718 var applyArgs = [appendArgs, 0].concat(args); // create method call params
719 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
721 return method.apply(obj || window, callArgs);
726 * Calls this function after the number of millseconds specified.
727 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
728 * @param {Object} obj (optional) The object for which the scope is set
729 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
730 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
731 * if a number the args are inserted at the specified position
732 * @return {Number} The timeout id that can be used with clearTimeout
734 defer : function(millis, obj, args, appendArgs){
735 var fn = this.createDelegate(obj, args, appendArgs);
737 return setTimeout(fn, millis);
743 * Create a combined function call sequence of the original function + the passed function.
744 * The resulting function returns the results of the original function.
745 * The passed fcn is called with the parameters of the original function
746 * @param {Function} fcn The function to sequence
747 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
748 * @return {Function} The new function
750 createSequence : function(fcn, scope){
751 if(typeof fcn != "function"){
756 var retval = method.apply(this || window, arguments);
757 fcn.apply(scope || this || window, arguments);
763 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
764 * The resulting function returns the results of the original function.
765 * The passed fcn is called with the parameters of the original function.
767 * @param {Function} fcn The function to call before the original
768 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
769 * @return {Function} The new function
771 createInterceptor : function(fcn, scope){
772 if(typeof fcn != "function"){
779 if(fcn.apply(scope || this || window, arguments) === false){
782 return method.apply(this || window, arguments);
788 * Ext JS Library 1.1.1
789 * Copyright(c) 2006-2007, Ext JS, LLC.
791 * Originally Released Under LGPL - original licence link has changed is not relivant.
794 * <script type="text/javascript">
797 Roo.applyIf(String, {
802 * Escapes the passed string for ' and \
803 * @param {String} string The string to escape
804 * @return {String} The escaped string
807 escape : function(string) {
808 return string.replace(/('|\\)/g, "\\$1");
812 * Pads the left side of a string with a specified character. This is especially useful
813 * for normalizing number and date strings. Example usage:
815 var s = String.leftPad('123', 5, '0');
816 // s now contains the string: '00123'
818 * @param {String} string The original string
819 * @param {Number} size The total length of the output string
820 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
821 * @return {String} The padded string
824 leftPad : function (val, size, ch) {
825 var result = new String(val);
826 if(ch === null || ch === undefined || ch === '') {
829 while (result.length < size) {
830 result = ch + result;
836 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
837 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
839 var cls = 'my-class', text = 'Some text';
840 var s = String.format('<div class="{0}">{1}</div>', cls, text);
841 // s now contains the string: '<div class="my-class">Some text</div>'
843 * @param {String} string The tokenized string to be formatted
844 * @param {String} value1 The value to replace token {0}
845 * @param {String} value2 Etc...
846 * @return {String} The formatted string
849 format : function(format){
850 var args = Array.prototype.slice.call(arguments, 1);
851 return format.replace(/\{(\d+)\}/g, function(m, i){
852 return Roo.util.Format.htmlEncode(args[i]);
858 * Utility function that allows you to easily switch a string between two alternating values. The passed value
859 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
860 * they are already different, the first value passed in is returned. Note that this method returns the new value
861 * but does not change the current string.
863 // alternate sort directions
864 sort = sort.toggle('ASC', 'DESC');
866 // instead of conditional logic:
867 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
869 * @param {String} value The value to compare to the current string
870 * @param {String} other The new value to use if the string already equals the first value passed in
871 * @return {String} The new value
874 String.prototype.toggle = function(value, other){
875 return this == value ? other : value;
878 * Ext JS Library 1.1.1
879 * Copyright(c) 2006-2007, Ext JS, LLC.
881 * Originally Released Under LGPL - original licence link has changed is not relivant.
884 * <script type="text/javascript">
890 Roo.applyIf(Number.prototype, {
892 * Checks whether or not the current number is within a desired range. If the number is already within the
893 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
894 * exceeded. Note that this method returns the constrained value but does not change the current number.
895 * @param {Number} min The minimum number in the range
896 * @param {Number} max The maximum number in the range
897 * @return {Number} The constrained value if outside the range, otherwise the current value
899 constrain : function(min, max){
900 return Math.min(Math.max(this, min), max);
904 * Ext JS Library 1.1.1
905 * Copyright(c) 2006-2007, Ext JS, LLC.
907 * Originally Released Under LGPL - original licence link has changed is not relivant.
910 * <script type="text/javascript">
915 Roo.applyIf(Array.prototype, {
917 * Checks whether or not the specified object exists in the array.
918 * @param {Object} o The object to check for
919 * @return {Number} The index of o in the array (or -1 if it is not found)
921 indexOf : function(o){
922 for (var i = 0, len = this.length; i < len; i++){
923 if(this[i] == o) return i;
929 * Removes the specified object from the array. If the object is not found nothing happens.
930 * @param {Object} o The object to remove
932 remove : function(o){
933 var index = this.indexOf(o);
935 this.splice(index, 1);
939 * Map (JS 1.6 compatibility)
940 * @param {Function} function to call
944 var len = this.length >>> 0;
945 if (typeof fun != "function")
946 throw new TypeError();
948 var res = new Array(len);
949 var thisp = arguments[1];
950 for (var i = 0; i < len; i++)
953 res[i] = fun.call(thisp, this[i], i, this);
964 * Ext JS Library 1.1.1
965 * Copyright(c) 2006-2007, Ext JS, LLC.
967 * Originally Released Under LGPL - original licence link has changed is not relivant.
970 * <script type="text/javascript">
976 * The date parsing and format syntax is a subset of
977 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
978 * supported will provide results equivalent to their PHP versions.
980 * Following is the list of all currently supported formats:
983 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
985 Format Output Description
986 ------ ---------- --------------------------------------------------------------
987 d 10 Day of the month, 2 digits with leading zeros
988 D Wed A textual representation of a day, three letters
989 j 10 Day of the month without leading zeros
990 l Wednesday A full textual representation of the day of the week
991 S th English ordinal day of month suffix, 2 chars (use with j)
992 w 3 Numeric representation of the day of the week
993 z 9 The julian date, or day of the year (0-365)
994 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
995 F January A full textual representation of the month
996 m 01 Numeric representation of a month, with leading zeros
997 M Jan Month name abbreviation, three letters
998 n 1 Numeric representation of a month, without leading zeros
999 t 31 Number of days in the given month
1000 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1001 Y 2007 A full numeric representation of a year, 4 digits
1002 y 07 A two digit representation of a year
1003 a pm Lowercase Ante meridiem and Post meridiem
1004 A PM Uppercase Ante meridiem and Post meridiem
1005 g 3 12-hour format of an hour without leading zeros
1006 G 15 24-hour format of an hour without leading zeros
1007 h 03 12-hour format of an hour with leading zeros
1008 H 15 24-hour format of an hour with leading zeros
1009 i 05 Minutes with leading zeros
1010 s 01 Seconds, with leading zeros
1011 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1012 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1013 T CST Timezone setting of the machine running the code
1014 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1017 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1019 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1020 document.write(dt.format('Y-m-d')); //2007-01-10
1021 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1022 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
1025 * Here are some standard date/time patterns that you might find helpful. They
1026 * are not part of the source of Date.js, but to use them you can simply copy this
1027 * block of code into any script that is included after Date.js and they will also become
1028 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1031 ISO8601Long:"Y-m-d H:i:s",
1032 ISO8601Short:"Y-m-d",
1034 LongDate: "l, F d, Y",
1035 FullDateTime: "l, F d, Y g:i:s A",
1038 LongTime: "g:i:s A",
1039 SortableDateTime: "Y-m-d\\TH:i:s",
1040 UniversalSortableDateTime: "Y-m-d H:i:sO",
1047 var dt = new Date();
1048 document.write(dt.format(Date.patterns.ShortDate));
1053 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1054 * They generate precompiled functions from date formats instead of parsing and
1055 * processing the pattern every time you format a date. These functions are available
1056 * on every Date object (any javascript function).
1058 * The original article and download are here:
1059 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1066 Returns the number of milliseconds between this date and date
1067 @param {Date} date (optional) Defaults to now
1068 @return {Number} The diff in milliseconds
1069 @member Date getElapsed
1071 Date.prototype.getElapsed = function(date) {
1072 return Math.abs((date || new Date()).getTime()-this.getTime());
1074 // was in date file..
1078 Date.parseFunctions = {count:0};
1080 Date.parseRegexes = [];
1082 Date.formatFunctions = {count:0};
1085 Date.prototype.dateFormat = function(format) {
1086 if (Date.formatFunctions[format] == null) {
1087 Date.createNewFormat(format);
1089 var func = Date.formatFunctions[format];
1090 return this[func]();
1095 * Formats a date given the supplied format string
1096 * @param {String} format The format string
1097 * @return {String} The formatted date
1100 Date.prototype.format = Date.prototype.dateFormat;
1103 Date.createNewFormat = function(format) {
1104 var funcName = "format" + Date.formatFunctions.count++;
1105 Date.formatFunctions[format] = funcName;
1106 var code = "Date.prototype." + funcName + " = function(){return ";
1107 var special = false;
1109 for (var i = 0; i < format.length; ++i) {
1110 ch = format.charAt(i);
1111 if (!special && ch == "\\") {
1116 code += "'" + String.escape(ch) + "' + ";
1119 code += Date.getFormatCode(ch);
1122 /** eval:var:zzzzzzzzzzzzz */
1123 eval(code.substring(0, code.length - 3) + ";}");
1127 Date.getFormatCode = function(character) {
1128 switch (character) {
1130 return "String.leftPad(this.getDate(), 2, '0') + ";
1132 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1134 return "this.getDate() + ";
1136 return "Date.dayNames[this.getDay()] + ";
1138 return "this.getSuffix() + ";
1140 return "this.getDay() + ";
1142 return "this.getDayOfYear() + ";
1144 return "this.getWeekOfYear() + ";
1146 return "Date.monthNames[this.getMonth()] + ";
1148 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1150 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1152 return "(this.getMonth() + 1) + ";
1154 return "this.getDaysInMonth() + ";
1156 return "(this.isLeapYear() ? 1 : 0) + ";
1158 return "this.getFullYear() + ";
1160 return "('' + this.getFullYear()).substring(2, 4) + ";
1162 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1164 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1166 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1168 return "this.getHours() + ";
1170 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1172 return "String.leftPad(this.getHours(), 2, '0') + ";
1174 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1176 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1178 return "this.getGMTOffset() + ";
1180 return "this.getGMTColonOffset() + ";
1182 return "this.getTimezone() + ";
1184 return "(this.getTimezoneOffset() * -60) + ";
1186 return "'" + String.escape(character) + "' + ";
1191 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1192 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1193 * the date format that is not specified will default to the current date value for that part. Time parts can also
1194 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1195 * string or the parse operation will fail.
1198 //dt = Fri May 25 2007 (current date)
1199 var dt = new Date();
1201 //dt = Thu May 25 2006 (today's month/day in 2006)
1202 dt = Date.parseDate("2006", "Y");
1204 //dt = Sun Jan 15 2006 (all date parts specified)
1205 dt = Date.parseDate("2006-1-15", "Y-m-d");
1207 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1208 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1210 * @param {String} input The unparsed date as a string
1211 * @param {String} format The format the date is in
1212 * @return {Date} The parsed date
1215 Date.parseDate = function(input, format) {
1216 if (Date.parseFunctions[format] == null) {
1217 Date.createParser(format);
1219 var func = Date.parseFunctions[format];
1220 return Date[func](input);
1225 Date.createParser = function(format) {
1226 var funcName = "parse" + Date.parseFunctions.count++;
1227 var regexNum = Date.parseRegexes.length;
1228 var currentGroup = 1;
1229 Date.parseFunctions[format] = funcName;
1231 var code = "Date." + funcName + " = function(input){\n"
1232 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1233 + "var d = new Date();\n"
1234 + "y = d.getFullYear();\n"
1235 + "m = d.getMonth();\n"
1236 + "d = d.getDate();\n"
1237 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1238 + "if (results && results.length > 0) {";
1241 var special = false;
1243 for (var i = 0; i < format.length; ++i) {
1244 ch = format.charAt(i);
1245 if (!special && ch == "\\") {
1250 regex += String.escape(ch);
1253 var obj = Date.formatCodeToRegex(ch, currentGroup);
1254 currentGroup += obj.g;
1256 if (obj.g && obj.c) {
1262 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1263 + "{v = new Date(y, m, d, h, i, s);}\n"
1264 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1265 + "{v = new Date(y, m, d, h, i);}\n"
1266 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1267 + "{v = new Date(y, m, d, h);}\n"
1268 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1269 + "{v = new Date(y, m, d);}\n"
1270 + "else if (y >= 0 && m >= 0)\n"
1271 + "{v = new Date(y, m);}\n"
1272 + "else if (y >= 0)\n"
1273 + "{v = new Date(y);}\n"
1274 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1275 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1276 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1279 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1280 /** eval:var:zzzzzzzzzzzzz */
1285 Date.formatCodeToRegex = function(character, currentGroup) {
1286 switch (character) {
1290 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1293 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1294 s:"(\\d{1,2})"}; // day of month without leading zeroes
1297 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298 s:"(\\d{2})"}; // day of month with leading zeroes
1302 s:"(?:" + Date.dayNames.join("|") + ")"};
1306 s:"(?:st|nd|rd|th)"};
1321 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1322 s:"(" + Date.monthNames.join("|") + ")"};
1325 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1326 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1329 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1330 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1333 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1345 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1349 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1350 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1354 c:"if (results[" + currentGroup + "] == 'am') {\n"
1355 + "if (h == 12) { h = 0; }\n"
1356 + "} else { if (h < 12) { h += 12; }}",
1360 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1361 + "if (h == 12) { h = 0; }\n"
1362 + "} else { if (h < 12) { h += 12; }}",
1367 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1372 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1373 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1376 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1380 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1385 "o = results[", currentGroup, "];\n",
1386 "var sn = o.substring(0,1);\n", // get + / - sign
1387 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1388 "var mn = o.substring(3,5) % 60;\n", // get minutes
1389 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1390 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1392 s:"([+\-]\\d{2,4})"};
1398 "o = results[", currentGroup, "];\n",
1399 "var sn = o.substring(0,1);\n",
1400 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1401 "var mn = o.substring(4,6) % 60;\n",
1402 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1403 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1409 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1412 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1413 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1414 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1418 s:String.escape(character)};
1423 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1424 * @return {String} The abbreviated timezone name (e.g. 'CST')
1426 Date.prototype.getTimezone = function() {
1427 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1431 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1432 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1434 Date.prototype.getGMTOffset = function() {
1435 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1436 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1437 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1441 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1442 * @return {String} 2-characters representing hours and 2-characters representing minutes
1443 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1445 Date.prototype.getGMTColonOffset = function() {
1446 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1447 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1449 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1453 * Get the numeric day number of the year, adjusted for leap year.
1454 * @return {Number} 0 through 364 (365 in leap years)
1456 Date.prototype.getDayOfYear = function() {
1458 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1459 for (var i = 0; i < this.getMonth(); ++i) {
1460 num += Date.daysInMonth[i];
1462 return num + this.getDate() - 1;
1466 * Get the string representation of the numeric week number of the year
1467 * (equivalent to the format specifier 'W').
1468 * @return {String} '00' through '52'
1470 Date.prototype.getWeekOfYear = function() {
1471 // Skip to Thursday of this week
1472 var now = this.getDayOfYear() + (4 - this.getDay());
1473 // Find the first Thursday of the year
1474 var jan1 = new Date(this.getFullYear(), 0, 1);
1475 var then = (7 - jan1.getDay() + 4);
1476 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1480 * Whether or not the current date is in a leap year.
1481 * @return {Boolean} True if the current date is in a leap year, else false
1483 Date.prototype.isLeapYear = function() {
1484 var year = this.getFullYear();
1485 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1489 * Get the first day of the current month, adjusted for leap year. The returned value
1490 * is the numeric day index within the week (0-6) which can be used in conjunction with
1491 * the {@link #monthNames} array to retrieve the textual day name.
1494 var dt = new Date('1/10/2007');
1495 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1497 * @return {Number} The day number (0-6)
1499 Date.prototype.getFirstDayOfMonth = function() {
1500 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1501 return (day < 0) ? (day + 7) : day;
1505 * Get the last day of the current month, adjusted for leap year. The returned value
1506 * is the numeric day index within the week (0-6) which can be used in conjunction with
1507 * the {@link #monthNames} array to retrieve the textual day name.
1510 var dt = new Date('1/10/2007');
1511 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1513 * @return {Number} The day number (0-6)
1515 Date.prototype.getLastDayOfMonth = function() {
1516 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1517 return (day < 0) ? (day + 7) : day;
1522 * Get the first date of this date's month
1525 Date.prototype.getFirstDateOfMonth = function() {
1526 return new Date(this.getFullYear(), this.getMonth(), 1);
1530 * Get the last date of this date's month
1533 Date.prototype.getLastDateOfMonth = function() {
1534 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1537 * Get the number of days in the current month, adjusted for leap year.
1538 * @return {Number} The number of days in the month
1540 Date.prototype.getDaysInMonth = function() {
1541 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1542 return Date.daysInMonth[this.getMonth()];
1546 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1547 * @return {String} 'st, 'nd', 'rd' or 'th'
1549 Date.prototype.getSuffix = function() {
1550 switch (this.getDate()) {
1567 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1570 * An array of textual month names.
1571 * Override these values for international dates, for example...
1572 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1591 * An array of textual day names.
1592 * Override these values for international dates, for example...
1593 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1609 Date.monthNumbers = {
1624 * Creates and returns a new Date instance with the exact same date value as the called instance.
1625 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1626 * variable will also be changed. When the intention is to create a new variable that will not
1627 * modify the original instance, you should create a clone.
1629 * Example of correctly cloning a date:
1632 var orig = new Date('10/1/2006');
1635 document.write(orig); //returns 'Thu Oct 05 2006'!
1638 var orig = new Date('10/1/2006');
1639 var copy = orig.clone();
1641 document.write(orig); //returns 'Thu Oct 01 2006'
1643 * @return {Date} The new Date instance
1645 Date.prototype.clone = function() {
1646 return new Date(this.getTime());
1650 * Clears any time information from this date
1651 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1652 @return {Date} this or the clone
1654 Date.prototype.clearTime = function(clone){
1656 return this.clone().clearTime();
1661 this.setMilliseconds(0);
1666 // safari setMonth is broken
1668 Date.brokenSetMonth = Date.prototype.setMonth;
1669 Date.prototype.setMonth = function(num){
1671 var n = Math.ceil(-num);
1672 var back_year = Math.ceil(n/12);
1673 var month = (n % 12) ? 12 - n % 12 : 0 ;
1674 this.setFullYear(this.getFullYear() - back_year);
1675 return Date.brokenSetMonth.call(this, month);
1677 return Date.brokenSetMonth.apply(this, arguments);
1682 /** Date interval constant
1686 /** Date interval constant
1690 /** Date interval constant
1694 /** Date interval constant
1698 /** Date interval constant
1702 /** Date interval constant
1706 /** Date interval constant
1712 * Provides a convenient method of performing basic date arithmetic. This method
1713 * does not modify the Date instance being called - it creates and returns
1714 * a new Date instance containing the resulting date value.
1719 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1720 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1722 //Negative values will subtract correctly:
1723 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1724 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1726 //You can even chain several calls together in one line!
1727 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1728 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1731 * @param {String} interval A valid date interval enum value
1732 * @param {Number} value The amount to add to the current date
1733 * @return {Date} The new Date instance
1735 Date.prototype.add = function(interval, value){
1736 var d = this.clone();
1737 if (!interval || value === 0) return d;
1738 switch(interval.toLowerCase()){
1740 d.setMilliseconds(this.getMilliseconds() + value);
1743 d.setSeconds(this.getSeconds() + value);
1746 d.setMinutes(this.getMinutes() + value);
1749 d.setHours(this.getHours() + value);
1752 d.setDate(this.getDate() + value);
1755 var day = this.getDate();
1757 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1760 d.setMonth(this.getMonth() + value);
1763 d.setFullYear(this.getFullYear() + value);
1770 * Ext JS Library 1.1.1
1771 * Copyright(c) 2006-2007, Ext JS, LLC.
1773 * Originally Released Under LGPL - original licence link has changed is not relivant.
1776 * <script type="text/javascript">
1780 * @class Roo.lib.Dom
1783 * Dom utils (from YIU afaik)
1788 * Get the view width
1789 * @param {Boolean} full True will get the full document, otherwise it's the view width
1790 * @return {Number} The width
1793 getViewWidth : function(full) {
1794 return full ? this.getDocumentWidth() : this.getViewportWidth();
1797 * Get the view height
1798 * @param {Boolean} full True will get the full document, otherwise it's the view height
1799 * @return {Number} The height
1801 getViewHeight : function(full) {
1802 return full ? this.getDocumentHeight() : this.getViewportHeight();
1805 getDocumentHeight: function() {
1806 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1807 return Math.max(scrollHeight, this.getViewportHeight());
1810 getDocumentWidth: function() {
1811 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1812 return Math.max(scrollWidth, this.getViewportWidth());
1815 getViewportHeight: function() {
1816 var height = self.innerHeight;
1817 var mode = document.compatMode;
1819 if ((mode || Roo.isIE) && !Roo.isOpera) {
1820 height = (mode == "CSS1Compat") ?
1821 document.documentElement.clientHeight :
1822 document.body.clientHeight;
1828 getViewportWidth: function() {
1829 var width = self.innerWidth;
1830 var mode = document.compatMode;
1832 if (mode || Roo.isIE) {
1833 width = (mode == "CSS1Compat") ?
1834 document.documentElement.clientWidth :
1835 document.body.clientWidth;
1840 isAncestor : function(p, c) {
1847 if (p.contains && !Roo.isSafari) {
1848 return p.contains(c);
1849 } else if (p.compareDocumentPosition) {
1850 return !!(p.compareDocumentPosition(c) & 16);
1852 var parent = c.parentNode;
1857 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1860 parent = parent.parentNode;
1866 getRegion : function(el) {
1867 return Roo.lib.Region.getRegion(el);
1870 getY : function(el) {
1871 return this.getXY(el)[1];
1874 getX : function(el) {
1875 return this.getXY(el)[0];
1878 getXY : function(el) {
1879 var p, pe, b, scroll, bd = document.body;
1880 el = Roo.getDom(el);
1881 var fly = Roo.lib.AnimBase.fly;
1882 if (el.getBoundingClientRect) {
1883 b = el.getBoundingClientRect();
1884 scroll = fly(document).getScroll();
1885 return [b.left + scroll.left, b.top + scroll.top];
1891 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1898 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1905 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1906 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1913 if (p != el && pe.getStyle('overflow') != 'visible') {
1921 if (Roo.isSafari && hasAbsolute) {
1926 if (Roo.isGecko && !hasAbsolute) {
1928 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1929 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1933 while (p && p != bd) {
1934 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1946 setXY : function(el, xy) {
1947 el = Roo.fly(el, '_setXY');
1949 var pts = el.translatePoints(xy);
1950 if (xy[0] !== false) {
1951 el.dom.style.left = pts.left + "px";
1953 if (xy[1] !== false) {
1954 el.dom.style.top = pts.top + "px";
1958 setX : function(el, x) {
1959 this.setXY(el, [x, false]);
1962 setY : function(el, y) {
1963 this.setXY(el, [false, y]);
1967 * Portions of this file are based on pieces of Yahoo User Interface Library
1968 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1969 * YUI licensed under the BSD License:
1970 * http://developer.yahoo.net/yui/license.txt
1971 * <script type="text/javascript">
1975 Roo.lib.Event = function() {
1976 var loadComplete = false;
1978 var unloadListeners = [];
1980 var onAvailStack = [];
1982 var lastError = null;
1995 startInterval: function() {
1996 if (!this._interval) {
1998 var callback = function() {
1999 self._tryPreloadAttach();
2001 this._interval = setInterval(callback, this.POLL_INTERVAL);
2006 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2007 onAvailStack.push({ id: p_id,
2010 override: p_override,
2011 checkReady: false });
2013 retryCount = this.POLL_RETRYS;
2014 this.startInterval();
2018 addListener: function(el, eventName, fn) {
2019 el = Roo.getDom(el);
2024 if ("unload" == eventName) {
2025 unloadListeners[unloadListeners.length] =
2026 [el, eventName, fn];
2030 var wrappedFn = function(e) {
2031 return fn(Roo.lib.Event.getEvent(e));
2034 var li = [el, eventName, fn, wrappedFn];
2036 var index = listeners.length;
2037 listeners[index] = li;
2039 this.doAdd(el, eventName, wrappedFn, false);
2045 removeListener: function(el, eventName, fn) {
2048 el = Roo.getDom(el);
2051 return this.purgeElement(el, false, eventName);
2055 if ("unload" == eventName) {
2057 for (i = 0,len = unloadListeners.length; i < len; i++) {
2058 var li = unloadListeners[i];
2061 li[1] == eventName &&
2063 unloadListeners.splice(i, 1);
2071 var cacheItem = null;
2074 var index = arguments[3];
2076 if ("undefined" == typeof index) {
2077 index = this._getCacheIndex(el, eventName, fn);
2081 cacheItem = listeners[index];
2084 if (!el || !cacheItem) {
2088 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2090 delete listeners[index][this.WFN];
2091 delete listeners[index][this.FN];
2092 listeners.splice(index, 1);
2099 getTarget: function(ev, resolveTextNode) {
2100 ev = ev.browserEvent || ev;
2101 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2102 var t = ev.target || ev.srcElement;
2103 return this.resolveTextNode(t);
2107 resolveTextNode: function(node) {
2108 if (Roo.isSafari && node && 3 == node.nodeType) {
2109 return node.parentNode;
2116 getPageX: function(ev) {
2117 ev = ev.browserEvent || ev;
2118 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2120 if (!x && 0 !== x) {
2121 x = ev.clientX || 0;
2124 x += this.getScroll()[1];
2132 getPageY: function(ev) {
2133 ev = ev.browserEvent || ev;
2134 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2136 if (!y && 0 !== y) {
2137 y = ev.clientY || 0;
2140 y += this.getScroll()[0];
2149 getXY: function(ev) {
2150 ev = ev.browserEvent || ev;
2151 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2152 return [this.getPageX(ev), this.getPageY(ev)];
2156 getRelatedTarget: function(ev) {
2157 ev = ev.browserEvent || ev;
2158 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2159 var t = ev.relatedTarget;
2161 if (ev.type == "mouseout") {
2163 } else if (ev.type == "mouseover") {
2168 return this.resolveTextNode(t);
2172 getTime: function(ev) {
2173 ev = ev.browserEvent || ev;
2174 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2176 var t = new Date().getTime();
2180 this.lastError = ex;
2189 stopEvent: function(ev) {
2190 this.stopPropagation(ev);
2191 this.preventDefault(ev);
2195 stopPropagation: function(ev) {
2196 ev = ev.browserEvent || ev;
2197 if (ev.stopPropagation) {
2198 ev.stopPropagation();
2200 ev.cancelBubble = true;
2205 preventDefault: function(ev) {
2206 ev = ev.browserEvent || ev;
2207 if(ev.preventDefault) {
2208 ev.preventDefault();
2210 ev.returnValue = false;
2215 getEvent: function(e) {
2216 var ev = e || window.event;
2218 var c = this.getEvent.caller;
2220 ev = c.arguments[0];
2221 if (ev && Event == ev.constructor) {
2231 getCharCode: function(ev) {
2232 ev = ev.browserEvent || ev;
2233 return ev.charCode || ev.keyCode || 0;
2237 _getCacheIndex: function(el, eventName, fn) {
2238 for (var i = 0,len = listeners.length; i < len; ++i) {
2239 var li = listeners[i];
2241 li[this.FN] == fn &&
2242 li[this.EL] == el &&
2243 li[this.TYPE] == eventName) {
2255 getEl: function(id) {
2256 return document.getElementById(id);
2260 clearCache: function() {
2264 _load: function(e) {
2265 loadComplete = true;
2266 var EU = Roo.lib.Event;
2270 EU.doRemove(window, "load", EU._load);
2275 _tryPreloadAttach: function() {
2284 var tryAgain = !loadComplete;
2286 tryAgain = (retryCount > 0);
2291 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2292 var item = onAvailStack[i];
2294 var el = this.getEl(item.id);
2297 if (!item.checkReady ||
2300 (document && document.body)) {
2303 if (item.override) {
2304 if (item.override === true) {
2307 scope = item.override;
2310 item.fn.call(scope, item.obj);
2311 onAvailStack[i] = null;
2314 notAvail.push(item);
2319 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2323 this.startInterval();
2325 clearInterval(this._interval);
2326 this._interval = null;
2329 this.locked = false;
2336 purgeElement: function(el, recurse, eventName) {
2337 var elListeners = this.getListeners(el, eventName);
2339 for (var i = 0,len = elListeners.length; i < len; ++i) {
2340 var l = elListeners[i];
2341 this.removeListener(el, l.type, l.fn);
2345 if (recurse && el && el.childNodes) {
2346 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2347 this.purgeElement(el.childNodes[i], recurse, eventName);
2353 getListeners: function(el, eventName) {
2354 var results = [], searchLists;
2356 searchLists = [listeners, unloadListeners];
2357 } else if (eventName == "unload") {
2358 searchLists = [unloadListeners];
2360 searchLists = [listeners];
2363 for (var j = 0; j < searchLists.length; ++j) {
2364 var searchList = searchLists[j];
2365 if (searchList && searchList.length > 0) {
2366 for (var i = 0,len = searchList.length; i < len; ++i) {
2367 var l = searchList[i];
2368 if (l && l[this.EL] === el &&
2369 (!eventName || eventName === l[this.TYPE])) {
2374 adjust: l[this.ADJ_SCOPE],
2382 return (results.length) ? results : null;
2386 _unload: function(e) {
2388 var EU = Roo.lib.Event, i, j, l, len, index;
2390 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2391 l = unloadListeners[i];
2394 if (l[EU.ADJ_SCOPE]) {
2395 if (l[EU.ADJ_SCOPE] === true) {
2398 scope = l[EU.ADJ_SCOPE];
2401 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2402 unloadListeners[i] = null;
2408 unloadListeners = null;
2410 if (listeners && listeners.length > 0) {
2411 j = listeners.length;
2414 l = listeners[index];
2416 EU.removeListener(l[EU.EL], l[EU.TYPE],
2426 EU.doRemove(window, "unload", EU._unload);
2431 getScroll: function() {
2432 var dd = document.documentElement, db = document.body;
2433 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2434 return [dd.scrollTop, dd.scrollLeft];
2436 return [db.scrollTop, db.scrollLeft];
2443 doAdd: function () {
2444 if (window.addEventListener) {
2445 return function(el, eventName, fn, capture) {
2446 el.addEventListener(eventName, fn, (capture));
2448 } else if (window.attachEvent) {
2449 return function(el, eventName, fn, capture) {
2450 el.attachEvent("on" + eventName, fn);
2459 doRemove: function() {
2460 if (window.removeEventListener) {
2461 return function (el, eventName, fn, capture) {
2462 el.removeEventListener(eventName, fn, (capture));
2464 } else if (window.detachEvent) {
2465 return function (el, eventName, fn) {
2466 el.detachEvent("on" + eventName, fn);
2478 var E = Roo.lib.Event;
2479 E.on = E.addListener;
2480 E.un = E.removeListener;
2482 if (document && document.body) {
2485 E.doAdd(window, "load", E._load);
2487 E.doAdd(window, "unload", E._unload);
2488 E._tryPreloadAttach();
2492 * Portions of this file are based on pieces of Yahoo User Interface Library
2493 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2494 * YUI licensed under the BSD License:
2495 * http://developer.yahoo.net/yui/license.txt
2496 * <script type="text/javascript">
2502 * @class Roo.lib.Ajax
2509 request : function(method, uri, cb, data, options) {
2511 var hs = options.headers;
2514 if(hs.hasOwnProperty(h)){
2515 this.initHeader(h, hs[h], false);
2519 if(options.xmlData){
2520 this.initHeader('Content-Type', 'text/xml', false);
2522 data = options.xmlData;
2526 return this.asyncRequest(method, uri, cb, data);
2529 serializeForm : function(form) {
2530 if(typeof form == 'string') {
2531 form = (document.getElementById(form) || document.forms[form]);
2534 var el, name, val, disabled, data = '', hasSubmit = false;
2535 for (var i = 0; i < form.elements.length; i++) {
2536 el = form.elements[i];
2537 disabled = form.elements[i].disabled;
2538 name = form.elements[i].name;
2539 val = form.elements[i].value;
2541 if (!disabled && name){
2545 case 'select-multiple':
2546 for (var j = 0; j < el.options.length; j++) {
2547 if (el.options[j].selected) {
2549 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2552 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2560 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2573 if(hasSubmit == false) {
2574 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2579 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2584 data = data.substr(0, data.length - 1);
2592 useDefaultHeader:true,
2594 defaultPostHeader:'application/x-www-form-urlencoded',
2596 useDefaultXhrHeader:true,
2598 defaultXhrHeader:'XMLHttpRequest',
2600 hasDefaultHeaders:true,
2612 setProgId:function(id)
2614 this.activeX.unshift(id);
2617 setDefaultPostHeader:function(b)
2619 this.useDefaultHeader = b;
2622 setDefaultXhrHeader:function(b)
2624 this.useDefaultXhrHeader = b;
2627 setPollingInterval:function(i)
2629 if (typeof i == 'number' && isFinite(i)) {
2630 this.pollInterval = i;
2634 createXhrObject:function(transactionId)
2640 http = new XMLHttpRequest();
2642 obj = { conn:http, tId:transactionId };
2646 for (var i = 0; i < this.activeX.length; ++i) {
2650 http = new ActiveXObject(this.activeX[i]);
2652 obj = { conn:http, tId:transactionId };
2665 getConnectionObject:function()
2668 var tId = this.transactionId;
2672 o = this.createXhrObject(tId);
2674 this.transactionId++;
2685 asyncRequest:function(method, uri, callback, postData)
2687 var o = this.getConnectionObject();
2693 o.conn.open(method, uri, true);
2695 if (this.useDefaultXhrHeader) {
2696 if (!this.defaultHeaders['X-Requested-With']) {
2697 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2701 if(postData && this.useDefaultHeader){
2702 this.initHeader('Content-Type', this.defaultPostHeader);
2705 if (this.hasDefaultHeaders || this.hasHeaders) {
2709 this.handleReadyState(o, callback);
2710 o.conn.send(postData || null);
2716 handleReadyState:function(o, callback)
2720 if (callback && callback.timeout) {
2722 this.timeout[o.tId] = window.setTimeout(function() {
2723 oConn.abort(o, callback, true);
2724 }, callback.timeout);
2727 this.poll[o.tId] = window.setInterval(
2729 if (o.conn && o.conn.readyState == 4) {
2730 window.clearInterval(oConn.poll[o.tId]);
2731 delete oConn.poll[o.tId];
2733 if(callback && callback.timeout) {
2734 window.clearTimeout(oConn.timeout[o.tId]);
2735 delete oConn.timeout[o.tId];
2738 oConn.handleTransactionResponse(o, callback);
2741 , this.pollInterval);
2744 handleTransactionResponse:function(o, callback, isAbort)
2748 this.releaseObject(o);
2752 var httpStatus, responseObject;
2756 if (o.conn.status !== undefined && o.conn.status != 0) {
2757 httpStatus = o.conn.status;
2769 if (httpStatus >= 200 && httpStatus < 300) {
2770 responseObject = this.createResponseObject(o, callback.argument);
2771 if (callback.success) {
2772 if (!callback.scope) {
2773 callback.success(responseObject);
2778 callback.success.apply(callback.scope, [responseObject]);
2783 switch (httpStatus) {
2791 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2792 if (callback.failure) {
2793 if (!callback.scope) {
2794 callback.failure(responseObject);
2797 callback.failure.apply(callback.scope, [responseObject]);
2802 responseObject = this.createResponseObject(o, callback.argument);
2803 if (callback.failure) {
2804 if (!callback.scope) {
2805 callback.failure(responseObject);
2808 callback.failure.apply(callback.scope, [responseObject]);
2814 this.releaseObject(o);
2815 responseObject = null;
2818 createResponseObject:function(o, callbackArg)
2825 var headerStr = o.conn.getAllResponseHeaders();
2826 var header = headerStr.split('\n');
2827 for (var i = 0; i < header.length; i++) {
2828 var delimitPos = header[i].indexOf(':');
2829 if (delimitPos != -1) {
2830 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2838 obj.status = o.conn.status;
2839 obj.statusText = o.conn.statusText;
2840 obj.getResponseHeader = headerObj;
2841 obj.getAllResponseHeaders = headerStr;
2842 obj.responseText = o.conn.responseText;
2843 obj.responseXML = o.conn.responseXML;
2845 if (typeof callbackArg !== undefined) {
2846 obj.argument = callbackArg;
2852 createExceptionObject:function(tId, callbackArg, isAbort)
2855 var COMM_ERROR = 'communication failure';
2856 var ABORT_CODE = -1;
2857 var ABORT_ERROR = 'transaction aborted';
2863 obj.status = ABORT_CODE;
2864 obj.statusText = ABORT_ERROR;
2867 obj.status = COMM_CODE;
2868 obj.statusText = COMM_ERROR;
2872 obj.argument = callbackArg;
2878 initHeader:function(label, value, isDefault)
2880 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2882 if (headerObj[label] === undefined) {
2883 headerObj[label] = value;
2888 headerObj[label] = value + "," + headerObj[label];
2892 this.hasDefaultHeaders = true;
2895 this.hasHeaders = true;
2900 setHeader:function(o)
2902 if (this.hasDefaultHeaders) {
2903 for (var prop in this.defaultHeaders) {
2904 if (this.defaultHeaders.hasOwnProperty(prop)) {
2905 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2910 if (this.hasHeaders) {
2911 for (var prop in this.headers) {
2912 if (this.headers.hasOwnProperty(prop)) {
2913 o.conn.setRequestHeader(prop, this.headers[prop]);
2917 this.hasHeaders = false;
2921 resetDefaultHeaders:function() {
2922 delete this.defaultHeaders;
2923 this.defaultHeaders = {};
2924 this.hasDefaultHeaders = false;
2927 abort:function(o, callback, isTimeout)
2929 if(this.isCallInProgress(o)) {
2931 window.clearInterval(this.poll[o.tId]);
2932 delete this.poll[o.tId];
2934 delete this.timeout[o.tId];
2937 this.handleTransactionResponse(o, callback, true);
2947 isCallInProgress:function(o)
2950 return o.conn.readyState != 4 && o.conn.readyState != 0;
2959 releaseObject:function(o)
2968 'MSXML2.XMLHTTP.3.0',
2976 * Portions of this file are based on pieces of Yahoo User Interface Library
2977 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2978 * YUI licensed under the BSD License:
2979 * http://developer.yahoo.net/yui/license.txt
2980 * <script type="text/javascript">
2984 Roo.lib.Region = function(t, r, b, l) {
2994 Roo.lib.Region.prototype = {
2995 contains : function(region) {
2996 return ( region.left >= this.left &&
2997 region.right <= this.right &&
2998 region.top >= this.top &&
2999 region.bottom <= this.bottom );
3003 getArea : function() {
3004 return ( (this.bottom - this.top) * (this.right - this.left) );
3007 intersect : function(region) {
3008 var t = Math.max(this.top, region.top);
3009 var r = Math.min(this.right, region.right);
3010 var b = Math.min(this.bottom, region.bottom);
3011 var l = Math.max(this.left, region.left);
3013 if (b >= t && r >= l) {
3014 return new Roo.lib.Region(t, r, b, l);
3019 union : function(region) {
3020 var t = Math.min(this.top, region.top);
3021 var r = Math.max(this.right, region.right);
3022 var b = Math.max(this.bottom, region.bottom);
3023 var l = Math.min(this.left, region.left);
3025 return new Roo.lib.Region(t, r, b, l);
3028 adjust : function(t, l, b, r) {
3037 Roo.lib.Region.getRegion = function(el) {
3038 var p = Roo.lib.Dom.getXY(el);
3041 var r = p[0] + el.offsetWidth;
3042 var b = p[1] + el.offsetHeight;
3045 return new Roo.lib.Region(t, r, b, l);
3048 * Portions of this file are based on pieces of Yahoo User Interface Library
3049 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3050 * YUI licensed under the BSD License:
3051 * http://developer.yahoo.net/yui/license.txt
3052 * <script type="text/javascript">
3055 //@@dep Roo.lib.Region
3058 Roo.lib.Point = function(x, y) {
3059 if (x instanceof Array) {
3063 this.x = this.right = this.left = this[0] = x;
3064 this.y = this.top = this.bottom = this[1] = y;
3067 Roo.lib.Point.prototype = new Roo.lib.Region();
3069 * Portions of this file are based on pieces of Yahoo User Interface Library
3070 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3071 * YUI licensed under the BSD License:
3072 * http://developer.yahoo.net/yui/license.txt
3073 * <script type="text/javascript">
3080 scroll : function(el, args, duration, easing, cb, scope) {
3081 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3084 motion : function(el, args, duration, easing, cb, scope) {
3085 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3088 color : function(el, args, duration, easing, cb, scope) {
3089 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3092 run : function(el, args, duration, easing, cb, scope, type) {
3093 type = type || Roo.lib.AnimBase;
3094 if (typeof easing == "string") {
3095 easing = Roo.lib.Easing[easing];
3097 var anim = new type(el, args, duration, easing);
3098 anim.animateX(function() {
3099 Roo.callback(cb, scope);
3105 * Portions of this file are based on pieces of Yahoo User Interface Library
3106 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3107 * YUI licensed under the BSD License:
3108 * http://developer.yahoo.net/yui/license.txt
3109 * <script type="text/javascript">
3117 if (!libFlyweight) {
3118 libFlyweight = new Roo.Element.Flyweight();
3120 libFlyweight.dom = el;
3121 return libFlyweight;
3124 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3128 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3130 this.init(el, attributes, duration, method);
3134 Roo.lib.AnimBase.fly = fly;
3138 Roo.lib.AnimBase.prototype = {
3140 toString: function() {
3141 var el = this.getEl();
3142 var id = el.id || el.tagName;
3143 return ("Anim " + id);
3147 noNegatives: /width|height|opacity|padding/i,
3148 offsetAttribute: /^((width|height)|(top|left))$/,
3149 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3150 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3154 doMethod: function(attr, start, end) {
3155 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3159 setAttribute: function(attr, val, unit) {
3160 if (this.patterns.noNegatives.test(attr)) {
3161 val = (val > 0) ? val : 0;
3164 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3168 getAttribute: function(attr) {
3169 var el = this.getEl();
3170 var val = fly(el).getStyle(attr);
3172 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3173 return parseFloat(val);
3176 var a = this.patterns.offsetAttribute.exec(attr) || [];
3177 var pos = !!( a[3] );
3178 var box = !!( a[2] );
3181 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3182 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3191 getDefaultUnit: function(attr) {
3192 if (this.patterns.defaultUnit.test(attr)) {
3199 animateX : function(callback, scope) {
3200 var f = function() {
3201 this.onComplete.removeListener(f);
3202 if (typeof callback == "function") {
3203 callback.call(scope || this, this);
3206 this.onComplete.addListener(f, this);
3211 setRuntimeAttribute: function(attr) {
3214 var attributes = this.attributes;
3216 this.runtimeAttributes[attr] = {};
3218 var isset = function(prop) {
3219 return (typeof prop !== 'undefined');
3222 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3226 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3229 if (isset(attributes[attr]['to'])) {
3230 end = attributes[attr]['to'];
3231 } else if (isset(attributes[attr]['by'])) {
3232 if (start.constructor == Array) {
3234 for (var i = 0, len = start.length; i < len; ++i) {
3235 end[i] = start[i] + attributes[attr]['by'][i];
3238 end = start + attributes[attr]['by'];
3242 this.runtimeAttributes[attr].start = start;
3243 this.runtimeAttributes[attr].end = end;
3246 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3250 init: function(el, attributes, duration, method) {
3252 var isAnimated = false;
3255 var startTime = null;
3258 var actualFrames = 0;
3261 el = Roo.getDom(el);
3264 this.attributes = attributes || {};
3267 this.duration = duration || 1;
3270 this.method = method || Roo.lib.Easing.easeNone;
3273 this.useSeconds = true;
3276 this.currentFrame = 0;
3279 this.totalFrames = Roo.lib.AnimMgr.fps;
3282 this.getEl = function() {
3287 this.isAnimated = function() {
3292 this.getStartTime = function() {
3296 this.runtimeAttributes = {};
3299 this.animate = function() {
3300 if (this.isAnimated()) {
3304 this.currentFrame = 0;
3306 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3308 Roo.lib.AnimMgr.registerElement(this);
3312 this.stop = function(finish) {
3314 this.currentFrame = this.totalFrames;
3315 this._onTween.fire();
3317 Roo.lib.AnimMgr.stop(this);
3320 var onStart = function() {
3321 this.onStart.fire();
3323 this.runtimeAttributes = {};
3324 for (var attr in this.attributes) {
3325 this.setRuntimeAttribute(attr);
3330 startTime = new Date();
3334 var onTween = function() {
3336 duration: new Date() - this.getStartTime(),
3337 currentFrame: this.currentFrame
3340 data.toString = function() {
3342 'duration: ' + data.duration +
3343 ', currentFrame: ' + data.currentFrame
3347 this.onTween.fire(data);
3349 var runtimeAttributes = this.runtimeAttributes;
3351 for (var attr in runtimeAttributes) {
3352 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3358 var onComplete = function() {
3359 var actual_duration = (new Date() - startTime) / 1000 ;
3362 duration: actual_duration,
3363 frames: actualFrames,
3364 fps: actualFrames / actual_duration
3367 data.toString = function() {
3369 'duration: ' + data.duration +
3370 ', frames: ' + data.frames +
3371 ', fps: ' + data.fps
3377 this.onComplete.fire(data);
3381 this._onStart = new Roo.util.Event(this);
3382 this.onStart = new Roo.util.Event(this);
3383 this.onTween = new Roo.util.Event(this);
3384 this._onTween = new Roo.util.Event(this);
3385 this.onComplete = new Roo.util.Event(this);
3386 this._onComplete = new Roo.util.Event(this);
3387 this._onStart.addListener(onStart);
3388 this._onTween.addListener(onTween);
3389 this._onComplete.addListener(onComplete);
3394 * Portions of this file are based on pieces of Yahoo User Interface Library
3395 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3396 * YUI licensed under the BSD License:
3397 * http://developer.yahoo.net/yui/license.txt
3398 * <script type="text/javascript">
3402 Roo.lib.AnimMgr = new function() {
3419 this.registerElement = function(tween) {
3420 queue[queue.length] = tween;
3422 tween._onStart.fire();
3427 this.unRegister = function(tween, index) {
3428 tween._onComplete.fire();
3429 index = index || getIndex(tween);
3431 queue.splice(index, 1);
3435 if (tweenCount <= 0) {
3441 this.start = function() {
3442 if (thread === null) {
3443 thread = setInterval(this.run, this.delay);
3448 this.stop = function(tween) {
3450 clearInterval(thread);
3452 for (var i = 0, len = queue.length; i < len; ++i) {
3453 if (queue[0].isAnimated()) {
3454 this.unRegister(queue[0], 0);
3463 this.unRegister(tween);
3468 this.run = function() {
3469 for (var i = 0, len = queue.length; i < len; ++i) {
3470 var tween = queue[i];
3471 if (!tween || !tween.isAnimated()) {
3475 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3477 tween.currentFrame += 1;
3479 if (tween.useSeconds) {
3480 correctFrame(tween);
3482 tween._onTween.fire();
3485 Roo.lib.AnimMgr.stop(tween, i);
3490 var getIndex = function(anim) {
3491 for (var i = 0, len = queue.length; i < len; ++i) {
3492 if (queue[i] == anim) {
3500 var correctFrame = function(tween) {
3501 var frames = tween.totalFrames;
3502 var frame = tween.currentFrame;
3503 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3504 var elapsed = (new Date() - tween.getStartTime());
3507 if (elapsed < tween.duration * 1000) {
3508 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3510 tweak = frames - (frame + 1);
3512 if (tweak > 0 && isFinite(tweak)) {
3513 if (tween.currentFrame + tweak >= frames) {
3514 tweak = frames - (frame + 1);
3517 tween.currentFrame += tweak;
3523 * Portions of this file are based on pieces of Yahoo User Interface Library
3524 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3525 * YUI licensed under the BSD License:
3526 * http://developer.yahoo.net/yui/license.txt
3527 * <script type="text/javascript">
3530 Roo.lib.Bezier = new function() {
3532 this.getPosition = function(points, t) {
3533 var n = points.length;
3536 for (var i = 0; i < n; ++i) {
3537 tmp[i] = [points[i][0], points[i][1]];
3540 for (var j = 1; j < n; ++j) {
3541 for (i = 0; i < n - j; ++i) {
3542 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3543 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3547 return [ tmp[0][0], tmp[0][1] ];
3551 * Portions of this file are based on pieces of Yahoo User Interface Library
3552 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3553 * YUI licensed under the BSD License:
3554 * http://developer.yahoo.net/yui/license.txt
3555 * <script type="text/javascript">
3560 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3561 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3564 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3566 var fly = Roo.lib.AnimBase.fly;
3568 var superclass = Y.ColorAnim.superclass;
3569 var proto = Y.ColorAnim.prototype;
3571 proto.toString = function() {
3572 var el = this.getEl();
3573 var id = el.id || el.tagName;
3574 return ("ColorAnim " + id);
3577 proto.patterns.color = /color$/i;
3578 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3579 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3580 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3581 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3584 proto.parseColor = function(s) {
3585 if (s.length == 3) {
3589 var c = this.patterns.hex.exec(s);
3590 if (c && c.length == 4) {
3591 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3594 c = this.patterns.rgb.exec(s);
3595 if (c && c.length == 4) {
3596 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3599 c = this.patterns.hex3.exec(s);
3600 if (c && c.length == 4) {
3601 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3606 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3607 proto.getAttribute = function(attr) {
3608 var el = this.getEl();
3609 if (this.patterns.color.test(attr)) {
3610 var val = fly(el).getStyle(attr);
3612 if (this.patterns.transparent.test(val)) {
3613 var parent = el.parentNode;
3614 val = fly(parent).getStyle(attr);
3616 while (parent && this.patterns.transparent.test(val)) {
3617 parent = parent.parentNode;
3618 val = fly(parent).getStyle(attr);
3619 if (parent.tagName.toUpperCase() == 'HTML') {
3625 val = superclass.getAttribute.call(this, attr);
3630 proto.getAttribute = function(attr) {
3631 var el = this.getEl();
3632 if (this.patterns.color.test(attr)) {
3633 var val = fly(el).getStyle(attr);
3635 if (this.patterns.transparent.test(val)) {
3636 var parent = el.parentNode;
3637 val = fly(parent).getStyle(attr);
3639 while (parent && this.patterns.transparent.test(val)) {
3640 parent = parent.parentNode;
3641 val = fly(parent).getStyle(attr);
3642 if (parent.tagName.toUpperCase() == 'HTML') {
3648 val = superclass.getAttribute.call(this, attr);
3654 proto.doMethod = function(attr, start, end) {
3657 if (this.patterns.color.test(attr)) {
3659 for (var i = 0, len = start.length; i < len; ++i) {
3660 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3663 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3666 val = superclass.doMethod.call(this, attr, start, end);
3672 proto.setRuntimeAttribute = function(attr) {
3673 superclass.setRuntimeAttribute.call(this, attr);
3675 if (this.patterns.color.test(attr)) {
3676 var attributes = this.attributes;
3677 var start = this.parseColor(this.runtimeAttributes[attr].start);
3678 var end = this.parseColor(this.runtimeAttributes[attr].end);
3680 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3681 end = this.parseColor(attributes[attr].by);
3683 for (var i = 0, len = start.length; i < len; ++i) {
3684 end[i] = start[i] + end[i];
3688 this.runtimeAttributes[attr].start = start;
3689 this.runtimeAttributes[attr].end = end;
3695 * Portions of this file are based on pieces of Yahoo User Interface Library
3696 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3697 * YUI licensed under the BSD License:
3698 * http://developer.yahoo.net/yui/license.txt
3699 * <script type="text/javascript">
3705 easeNone: function (t, b, c, d) {
3706 return c * t / d + b;
3710 easeIn: function (t, b, c, d) {
3711 return c * (t /= d) * t + b;
3715 easeOut: function (t, b, c, d) {
3716 return -c * (t /= d) * (t - 2) + b;
3720 easeBoth: function (t, b, c, d) {
3721 if ((t /= d / 2) < 1) {
3722 return c / 2 * t * t + b;
3725 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3729 easeInStrong: function (t, b, c, d) {
3730 return c * (t /= d) * t * t * t + b;
3734 easeOutStrong: function (t, b, c, d) {
3735 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3739 easeBothStrong: function (t, b, c, d) {
3740 if ((t /= d / 2) < 1) {
3741 return c / 2 * t * t * t * t + b;
3744 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3749 elasticIn: function (t, b, c, d, a, p) {
3753 if ((t /= d) == 1) {
3760 if (!a || a < Math.abs(c)) {
3765 var s = p / (2 * Math.PI) * Math.asin(c / a);
3768 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3772 elasticOut: function (t, b, c, d, a, p) {
3776 if ((t /= d) == 1) {
3783 if (!a || a < Math.abs(c)) {
3788 var s = p / (2 * Math.PI) * Math.asin(c / a);
3791 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3795 elasticBoth: function (t, b, c, d, a, p) {
3800 if ((t /= d / 2) == 2) {
3808 if (!a || a < Math.abs(c)) {
3813 var s = p / (2 * Math.PI) * Math.asin(c / a);
3817 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3818 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3820 return a * Math.pow(2, -10 * (t -= 1)) *
3821 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3826 backIn: function (t, b, c, d, s) {
3827 if (typeof s == 'undefined') {
3830 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3834 backOut: function (t, b, c, d, s) {
3835 if (typeof s == 'undefined') {
3838 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3842 backBoth: function (t, b, c, d, s) {
3843 if (typeof s == 'undefined') {
3847 if ((t /= d / 2 ) < 1) {
3848 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3850 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3854 bounceIn: function (t, b, c, d) {
3855 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3859 bounceOut: function (t, b, c, d) {
3860 if ((t /= d) < (1 / 2.75)) {
3861 return c * (7.5625 * t * t) + b;
3862 } else if (t < (2 / 2.75)) {
3863 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3864 } else if (t < (2.5 / 2.75)) {
3865 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3867 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3871 bounceBoth: function (t, b, c, d) {
3873 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3875 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3878 * Portions of this file are based on pieces of Yahoo User Interface Library
3879 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3880 * YUI licensed under the BSD License:
3881 * http://developer.yahoo.net/yui/license.txt
3882 * <script type="text/javascript">
3886 Roo.lib.Motion = function(el, attributes, duration, method) {
3888 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3892 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3896 var superclass = Y.Motion.superclass;
3897 var proto = Y.Motion.prototype;
3899 proto.toString = function() {
3900 var el = this.getEl();
3901 var id = el.id || el.tagName;
3902 return ("Motion " + id);
3905 proto.patterns.points = /^points$/i;
3907 proto.setAttribute = function(attr, val, unit) {
3908 if (this.patterns.points.test(attr)) {
3909 unit = unit || 'px';
3910 superclass.setAttribute.call(this, 'left', val[0], unit);
3911 superclass.setAttribute.call(this, 'top', val[1], unit);
3913 superclass.setAttribute.call(this, attr, val, unit);
3917 proto.getAttribute = function(attr) {
3918 if (this.patterns.points.test(attr)) {
3920 superclass.getAttribute.call(this, 'left'),
3921 superclass.getAttribute.call(this, 'top')
3924 val = superclass.getAttribute.call(this, attr);
3930 proto.doMethod = function(attr, start, end) {
3933 if (this.patterns.points.test(attr)) {
3934 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3935 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3937 val = superclass.doMethod.call(this, attr, start, end);
3942 proto.setRuntimeAttribute = function(attr) {
3943 if (this.patterns.points.test(attr)) {
3944 var el = this.getEl();
3945 var attributes = this.attributes;
3947 var control = attributes['points']['control'] || [];
3951 if (control.length > 0 && !(control[0] instanceof Array)) {
3952 control = [control];
3955 for (i = 0,len = control.length; i < len; ++i) {
3956 tmp[i] = control[i];
3961 Roo.fly(el).position();
3963 if (isset(attributes['points']['from'])) {
3964 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3967 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3970 start = this.getAttribute('points');
3973 if (isset(attributes['points']['to'])) {
3974 end = translateValues.call(this, attributes['points']['to'], start);
3976 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3977 for (i = 0,len = control.length; i < len; ++i) {
3978 control[i] = translateValues.call(this, control[i], start);
3982 } else if (isset(attributes['points']['by'])) {
3983 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3985 for (i = 0,len = control.length; i < len; ++i) {
3986 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3990 this.runtimeAttributes[attr] = [start];
3992 if (control.length > 0) {
3993 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3996 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3999 superclass.setRuntimeAttribute.call(this, attr);
4003 var translateValues = function(val, start) {
4004 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4005 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4010 var isset = function(prop) {
4011 return (typeof prop !== 'undefined');
4015 * Portions of this file are based on pieces of Yahoo User Interface Library
4016 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4017 * YUI licensed under the BSD License:
4018 * http://developer.yahoo.net/yui/license.txt
4019 * <script type="text/javascript">
4023 Roo.lib.Scroll = function(el, attributes, duration, method) {
4025 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4029 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4033 var superclass = Y.Scroll.superclass;
4034 var proto = Y.Scroll.prototype;
4036 proto.toString = function() {
4037 var el = this.getEl();
4038 var id = el.id || el.tagName;
4039 return ("Scroll " + id);
4042 proto.doMethod = function(attr, start, end) {
4045 if (attr == 'scroll') {
4047 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4048 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4052 val = superclass.doMethod.call(this, attr, start, end);
4057 proto.getAttribute = function(attr) {
4059 var el = this.getEl();
4061 if (attr == 'scroll') {
4062 val = [ el.scrollLeft, el.scrollTop ];
4064 val = superclass.getAttribute.call(this, attr);
4070 proto.setAttribute = function(attr, val, unit) {
4071 var el = this.getEl();
4073 if (attr == 'scroll') {
4074 el.scrollLeft = val[0];
4075 el.scrollTop = val[1];
4077 superclass.setAttribute.call(this, attr, val, unit);
4083 * Ext JS Library 1.1.1
4084 * Copyright(c) 2006-2007, Ext JS, LLC.
4086 * Originally Released Under LGPL - original licence link has changed is not relivant.
4089 * <script type="text/javascript">
4093 // nasty IE9 hack - what a pile of crap that is..
4095 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4096 Range.prototype.createContextualFragment = function (html) {
4097 var doc = window.document;
4098 var container = doc.createElement("div");
4099 container.innerHTML = html;
4100 var frag = doc.createDocumentFragment(), n;
4101 while ((n = container.firstChild)) {
4102 frag.appendChild(n);
4109 * @class Roo.DomHelper
4110 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4111 * 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>.
4114 Roo.DomHelper = function(){
4115 var tempTableEl = null;
4116 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4117 var tableRe = /^table|tbody|tr|td$/i;
4119 // build as innerHTML where available
4121 var createHtml = function(o){
4122 if(typeof o == 'string'){
4131 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4132 if(attr == "style"){
4134 if(typeof s == "function"){
4137 if(typeof s == "string"){
4138 b += ' style="' + s + '"';
4139 }else if(typeof s == "object"){
4142 if(typeof s[key] != "function"){
4143 b += key + ":" + s[key] + ";";
4150 b += ' class="' + o["cls"] + '"';
4151 }else if(attr == "htmlFor"){
4152 b += ' for="' + o["htmlFor"] + '"';
4154 b += " " + attr + '="' + o[attr] + '"';
4158 if(emptyTags.test(o.tag)){
4162 var cn = o.children || o.cn;
4164 //http://bugs.kde.org/show_bug.cgi?id=71506
4165 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4166 for(var i = 0, len = cn.length; i < len; i++) {
4167 b += createHtml(cn[i], b);
4170 b += createHtml(cn, b);
4176 b += "</" + o.tag + ">";
4183 var createDom = function(o, parentNode){
4185 // defininition craeted..
4187 if (o.ns && o.ns != 'html') {
4189 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4190 xmlns[o.ns] = o.xmlns;
4193 if (typeof(xmlns[o.ns]) == 'undefined') {
4194 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4200 if (typeof(o) == 'string') {
4201 return parentNode.appendChild(document.createTextNode(o));
4203 o.tag = o.tag || div;
4204 if (o.ns && Roo.isIE) {
4206 o.tag = o.ns + ':' + o.tag;
4209 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4210 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4213 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4214 attr == "style" || typeof o[attr] == "function") continue;
4216 if(attr=="cls" && Roo.isIE){
4217 el.className = o["cls"];
4219 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4220 else el[attr] = o[attr];
4223 Roo.DomHelper.applyStyles(el, o.style);
4224 var cn = o.children || o.cn;
4226 //http://bugs.kde.org/show_bug.cgi?id=71506
4227 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4228 for(var i = 0, len = cn.length; i < len; i++) {
4229 createDom(cn[i], el);
4236 el.innerHTML = o.html;
4239 parentNode.appendChild(el);
4244 var ieTable = function(depth, s, h, e){
4245 tempTableEl.innerHTML = [s, h, e].join('');
4246 var i = -1, el = tempTableEl;
4253 // kill repeat to save bytes
4257 tbe = '</tbody>'+te,
4263 * Nasty code for IE's broken table implementation
4265 var insertIntoTable = function(tag, where, el, html){
4267 tempTableEl = document.createElement('div');
4272 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4275 if(where == 'beforebegin'){
4279 before = el.nextSibling;
4282 node = ieTable(4, trs, html, tre);
4284 else if(tag == 'tr'){
4285 if(where == 'beforebegin'){
4288 node = ieTable(3, tbs, html, tbe);
4289 } else if(where == 'afterend'){
4290 before = el.nextSibling;
4292 node = ieTable(3, tbs, html, tbe);
4293 } else{ // INTO a TR
4294 if(where == 'afterbegin'){
4295 before = el.firstChild;
4297 node = ieTable(4, trs, html, tre);
4299 } else if(tag == 'tbody'){
4300 if(where == 'beforebegin'){
4303 node = ieTable(2, ts, html, te);
4304 } else if(where == 'afterend'){
4305 before = el.nextSibling;
4307 node = ieTable(2, ts, html, te);
4309 if(where == 'afterbegin'){
4310 before = el.firstChild;
4312 node = ieTable(3, tbs, html, tbe);
4315 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4318 if(where == 'afterbegin'){
4319 before = el.firstChild;
4321 node = ieTable(2, ts, html, te);
4323 el.insertBefore(node, before);
4328 /** True to force the use of DOM instead of html fragments @type Boolean */
4332 * Returns the markup for the passed Element(s) config
4333 * @param {Object} o The Dom object spec (and children)
4336 markup : function(o){
4337 return createHtml(o);
4341 * Applies a style specification to an element
4342 * @param {String/HTMLElement} el The element to apply styles to
4343 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4344 * a function which returns such a specification.
4346 applyStyles : function(el, styles){
4349 if(typeof styles == "string"){
4350 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4352 while ((matches = re.exec(styles)) != null){
4353 el.setStyle(matches[1], matches[2]);
4355 }else if (typeof styles == "object"){
4356 for (var style in styles){
4357 el.setStyle(style, styles[style]);
4359 }else if (typeof styles == "function"){
4360 Roo.DomHelper.applyStyles(el, styles.call());
4366 * Inserts an HTML fragment into the Dom
4367 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4368 * @param {HTMLElement} el The context element
4369 * @param {String} html The HTML fragmenet
4370 * @return {HTMLElement} The new node
4372 insertHtml : function(where, el, html){
4373 where = where.toLowerCase();
4374 if(el.insertAdjacentHTML){
4375 if(tableRe.test(el.tagName)){
4377 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4383 el.insertAdjacentHTML('BeforeBegin', html);
4384 return el.previousSibling;
4386 el.insertAdjacentHTML('AfterBegin', html);
4387 return el.firstChild;
4389 el.insertAdjacentHTML('BeforeEnd', html);
4390 return el.lastChild;
4392 el.insertAdjacentHTML('AfterEnd', html);
4393 return el.nextSibling;
4395 throw 'Illegal insertion point -> "' + where + '"';
4397 var range = el.ownerDocument.createRange();
4401 range.setStartBefore(el);
4402 frag = range.createContextualFragment(html);
4403 el.parentNode.insertBefore(frag, el);
4404 return el.previousSibling;
4407 range.setStartBefore(el.firstChild);
4408 frag = range.createContextualFragment(html);
4409 el.insertBefore(frag, el.firstChild);
4410 return el.firstChild;
4412 el.innerHTML = html;
4413 return el.firstChild;
4417 range.setStartAfter(el.lastChild);
4418 frag = range.createContextualFragment(html);
4419 el.appendChild(frag);
4420 return el.lastChild;
4422 el.innerHTML = html;
4423 return el.lastChild;
4426 range.setStartAfter(el);
4427 frag = range.createContextualFragment(html);
4428 el.parentNode.insertBefore(frag, el.nextSibling);
4429 return el.nextSibling;
4431 throw 'Illegal insertion point -> "' + where + '"';
4435 * Creates new Dom element(s) and inserts them before el
4436 * @param {String/HTMLElement/Element} el The context element
4437 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4438 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4439 * @return {HTMLElement/Roo.Element} The new node
4441 insertBefore : function(el, o, returnElement){
4442 return this.doInsert(el, o, returnElement, "beforeBegin");
4446 * Creates new Dom element(s) and inserts them after el
4447 * @param {String/HTMLElement/Element} el The context element
4448 * @param {Object} o The Dom object spec (and children)
4449 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4450 * @return {HTMLElement/Roo.Element} The new node
4452 insertAfter : function(el, o, returnElement){
4453 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4457 * Creates new Dom element(s) and inserts them as the first child of el
4458 * @param {String/HTMLElement/Element} el The context element
4459 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4460 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4461 * @return {HTMLElement/Roo.Element} The new node
4463 insertFirst : function(el, o, returnElement){
4464 return this.doInsert(el, o, returnElement, "afterBegin");
4468 doInsert : function(el, o, returnElement, pos, sibling){
4469 el = Roo.getDom(el);
4471 if(this.useDom || o.ns){
4472 newNode = createDom(o, null);
4473 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4475 var html = createHtml(o);
4476 newNode = this.insertHtml(pos, el, html);
4478 return returnElement ? Roo.get(newNode, true) : newNode;
4482 * Creates new Dom element(s) and appends them to el
4483 * @param {String/HTMLElement/Element} el The context element
4484 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486 * @return {HTMLElement/Roo.Element} The new node
4488 append : function(el, o, returnElement){
4489 el = Roo.getDom(el);
4491 if(this.useDom || o.ns){
4492 newNode = createDom(o, null);
4493 el.appendChild(newNode);
4495 var html = createHtml(o);
4496 newNode = this.insertHtml("beforeEnd", el, html);
4498 return returnElement ? Roo.get(newNode, true) : newNode;
4502 * Creates new Dom element(s) and overwrites the contents of el with them
4503 * @param {String/HTMLElement/Element} el The context element
4504 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4505 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4506 * @return {HTMLElement/Roo.Element} The new node
4508 overwrite : function(el, o, returnElement){
4509 el = Roo.getDom(el);
4512 while (el.childNodes.length) {
4513 el.removeChild(el.firstChild);
4517 el.innerHTML = createHtml(o);
4520 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4524 * Creates a new Roo.DomHelper.Template from the Dom object spec
4525 * @param {Object} o The Dom object spec (and children)
4526 * @return {Roo.DomHelper.Template} The new template
4528 createTemplate : function(o){
4529 var html = createHtml(o);
4530 return new Roo.Template(html);
4536 * Ext JS Library 1.1.1
4537 * Copyright(c) 2006-2007, Ext JS, LLC.
4539 * Originally Released Under LGPL - original licence link has changed is not relivant.
4542 * <script type="text/javascript">
4546 * @class Roo.Template
4547 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4548 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4551 var t = new Roo.Template({
4552 html : '<div name="{id}">' +
4553 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4555 myformat: function (value, allValues) {
4556 return 'XX' + value;
4559 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4561 * For more information see this blog post with examples:
4562 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4563 - Create Elements using DOM, HTML fragments and Templates</a>.
4565 * @param {Object} cfg - Configuration object.
4567 Roo.Template = function(cfg){
4569 if(cfg instanceof Array){
4571 }else if(arguments.length > 1){
4572 cfg = Array.prototype.join.call(arguments, "");
4576 if (typeof(cfg) == 'object') {
4587 Roo.Template.prototype = {
4590 * @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..
4591 * it should be fixed so that template is observable...
4595 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4599 * Returns an HTML fragment of this template with the specified values applied.
4600 * @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'})
4601 * @return {String} The HTML fragment
4603 applyTemplate : function(values){
4607 return this.compiled(values);
4609 var useF = this.disableFormats !== true;
4610 var fm = Roo.util.Format, tpl = this;
4611 var fn = function(m, name, format, args){
4613 if(format.substr(0, 5) == "this."){
4614 return tpl.call(format.substr(5), values[name], values);
4617 // quoted values are required for strings in compiled templates,
4618 // but for non compiled we need to strip them
4619 // quoted reversed for jsmin
4620 var re = /^\s*['"](.*)["']\s*$/;
4621 args = args.split(',');
4622 for(var i = 0, len = args.length; i < len; i++){
4623 args[i] = args[i].replace(re, "$1");
4625 args = [values[name]].concat(args);
4627 args = [values[name]];
4629 return fm[format].apply(fm, args);
4632 return values[name] !== undefined ? values[name] : "";
4635 return this.html.replace(this.re, fn);
4653 this.loading = true;
4654 this.compiled = false;
4656 var cx = new Roo.data.Connection();
4660 success : function (response) {
4662 _t.html = response.responseText;
4666 failure : function(response) {
4667 Roo.log("Template failed to load from " + _t.url);
4674 * Sets the HTML used as the template and optionally compiles it.
4675 * @param {String} html
4676 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4677 * @return {Roo.Template} this
4679 set : function(html, compile){
4681 this.compiled = null;
4689 * True to disable format functions (defaults to false)
4692 disableFormats : false,
4695 * The regular expression used to match template variables
4699 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4702 * Compiles the template into an internal function, eliminating the RegEx overhead.
4703 * @return {Roo.Template} this
4705 compile : function(){
4706 var fm = Roo.util.Format;
4707 var useF = this.disableFormats !== true;
4708 var sep = Roo.isGecko ? "+" : ",";
4709 var fn = function(m, name, format, args){
4711 args = args ? ',' + args : "";
4712 if(format.substr(0, 5) != "this."){
4713 format = "fm." + format + '(';
4715 format = 'this.call("'+ format.substr(5) + '", ';
4719 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4721 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4724 // branched to use + in gecko and [].join() in others
4726 body = "this.compiled = function(values){ return '" +
4727 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4730 body = ["this.compiled = function(values){ return ['"];
4731 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4732 body.push("'].join('');};");
4733 body = body.join('');
4743 // private function used to call members
4744 call : function(fnName, value, allValues){
4745 return this[fnName](value, allValues);
4749 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4750 * @param {String/HTMLElement/Roo.Element} el The context element
4751 * @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'})
4752 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4753 * @return {HTMLElement/Roo.Element} The new node or Element
4755 insertFirst: function(el, values, returnElement){
4756 return this.doInsert('afterBegin', el, values, returnElement);
4760 * Applies the supplied values to the template and inserts the new node(s) before el.
4761 * @param {String/HTMLElement/Roo.Element} el The context element
4762 * @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'})
4763 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4764 * @return {HTMLElement/Roo.Element} The new node or Element
4766 insertBefore: function(el, values, returnElement){
4767 return this.doInsert('beforeBegin', el, values, returnElement);
4771 * Applies the supplied values to the template and inserts the new node(s) after el.
4772 * @param {String/HTMLElement/Roo.Element} el The context element
4773 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4774 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775 * @return {HTMLElement/Roo.Element} The new node or Element
4777 insertAfter : function(el, values, returnElement){
4778 return this.doInsert('afterEnd', el, values, returnElement);
4782 * Applies the supplied values to the template and appends the new node(s) to el.
4783 * @param {String/HTMLElement/Roo.Element} el The context element
4784 * @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'})
4785 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4786 * @return {HTMLElement/Roo.Element} The new node or Element
4788 append : function(el, values, returnElement){
4789 return this.doInsert('beforeEnd', el, values, returnElement);
4792 doInsert : function(where, el, values, returnEl){
4793 el = Roo.getDom(el);
4794 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4795 return returnEl ? Roo.get(newNode, true) : newNode;
4799 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4800 * @param {String/HTMLElement/Roo.Element} el The context element
4801 * @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'})
4802 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4803 * @return {HTMLElement/Roo.Element} The new node or Element
4805 overwrite : function(el, values, returnElement){
4806 el = Roo.getDom(el);
4807 el.innerHTML = this.applyTemplate(values);
4808 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4812 * Alias for {@link #applyTemplate}
4815 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4818 Roo.DomHelper.Template = Roo.Template;
4821 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4822 * @param {String/HTMLElement} el A DOM element or its id
4823 * @returns {Roo.Template} The created template
4826 Roo.Template.from = function(el){
4827 el = Roo.getDom(el);
4828 return new Roo.Template(el.value || el.innerHTML);
4831 * Ext JS Library 1.1.1
4832 * Copyright(c) 2006-2007, Ext JS, LLC.
4834 * Originally Released Under LGPL - original licence link has changed is not relivant.
4837 * <script type="text/javascript">
4842 * This is code is also distributed under MIT license for use
4843 * with jQuery and prototype JavaScript libraries.
4846 * @class Roo.DomQuery
4847 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).
4849 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>
4852 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.
4854 <h4>Element Selectors:</h4>
4856 <li> <b>*</b> any element</li>
4857 <li> <b>E</b> an element with the tag E</li>
4858 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4859 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4860 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4861 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4863 <h4>Attribute Selectors:</h4>
4864 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4866 <li> <b>E[foo]</b> has an attribute "foo"</li>
4867 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4868 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4869 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4870 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4871 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4872 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4874 <h4>Pseudo Classes:</h4>
4876 <li> <b>E:first-child</b> E is the first child of its parent</li>
4877 <li> <b>E:last-child</b> E is the last child of its parent</li>
4878 <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>
4879 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4880 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4881 <li> <b>E:only-child</b> E is the only child of its parent</li>
4882 <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>
4883 <li> <b>E:first</b> the first E in the resultset</li>
4884 <li> <b>E:last</b> the last E in the resultset</li>
4885 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4886 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4887 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4888 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4889 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4890 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4891 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4892 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4893 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4895 <h4>CSS Value Selectors:</h4>
4897 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4898 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4899 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4900 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4901 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4902 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4906 Roo.DomQuery = function(){
4907 var cache = {}, simpleCache = {}, valueCache = {};
4908 var nonSpace = /\S/;
4909 var trimRe = /^\s+|\s+$/g;
4910 var tplRe = /\{(\d+)\}/g;
4911 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4912 var tagTokenRe = /^(#)?([\w-\*]+)/;
4913 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4915 function child(p, index){
4917 var n = p.firstChild;
4919 if(n.nodeType == 1){
4930 while((n = n.nextSibling) && n.nodeType != 1);
4935 while((n = n.previousSibling) && n.nodeType != 1);
4939 function children(d){
4940 var n = d.firstChild, ni = -1;
4942 var nx = n.nextSibling;
4943 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4953 function byClassName(c, a, v){
4957 var r = [], ri = -1, cn;
4958 for(var i = 0, ci; ci = c[i]; i++){
4959 if((' '+ci.className+' ').indexOf(v) != -1){
4966 function attrValue(n, attr){
4967 if(!n.tagName && typeof n.length != "undefined"){
4976 if(attr == "class" || attr == "className"){
4979 return n.getAttribute(attr) || n[attr];
4983 function getNodes(ns, mode, tagName){
4984 var result = [], ri = -1, cs;
4988 tagName = tagName || "*";
4989 if(typeof ns.getElementsByTagName != "undefined"){
4993 for(var i = 0, ni; ni = ns[i]; i++){
4994 cs = ni.getElementsByTagName(tagName);
4995 for(var j = 0, ci; ci = cs[j]; j++){
4999 }else if(mode == "/" || mode == ">"){
5000 var utag = tagName.toUpperCase();
5001 for(var i = 0, ni, cn; ni = ns[i]; i++){
5002 cn = ni.children || ni.childNodes;
5003 for(var j = 0, cj; cj = cn[j]; j++){
5004 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5009 }else if(mode == "+"){
5010 var utag = tagName.toUpperCase();
5011 for(var i = 0, n; n = ns[i]; i++){
5012 while((n = n.nextSibling) && n.nodeType != 1);
5013 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5017 }else if(mode == "~"){
5018 for(var i = 0, n; n = ns[i]; i++){
5019 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5028 function concat(a, b){
5032 for(var i = 0, l = b.length; i < l; i++){
5038 function byTag(cs, tagName){
5039 if(cs.tagName || cs == document){
5045 var r = [], ri = -1;
5046 tagName = tagName.toLowerCase();
5047 for(var i = 0, ci; ci = cs[i]; i++){
5048 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5055 function byId(cs, attr, id){
5056 if(cs.tagName || cs == document){
5062 var r = [], ri = -1;
5063 for(var i = 0,ci; ci = cs[i]; i++){
5064 if(ci && ci.id == id){
5072 function byAttribute(cs, attr, value, op, custom){
5073 var r = [], ri = -1, st = custom=="{";
5074 var f = Roo.DomQuery.operators[op];
5075 for(var i = 0, ci; ci = cs[i]; i++){
5078 a = Roo.DomQuery.getStyle(ci, attr);
5080 else if(attr == "class" || attr == "className"){
5082 }else if(attr == "for"){
5084 }else if(attr == "href"){
5085 a = ci.getAttribute("href", 2);
5087 a = ci.getAttribute(attr);
5089 if((f && f(a, value)) || (!f && a)){
5096 function byPseudo(cs, name, value){
5097 return Roo.DomQuery.pseudos[name](cs, value);
5100 // This is for IE MSXML which does not support expandos.
5101 // IE runs the same speed using setAttribute, however FF slows way down
5102 // and Safari completely fails so they need to continue to use expandos.
5103 var isIE = window.ActiveXObject ? true : false;
5105 // this eval is stop the compressor from
5106 // renaming the variable to something shorter
5108 /** eval:var:batch */
5113 function nodupIEXml(cs){
5115 cs[0].setAttribute("_nodup", d);
5117 for(var i = 1, len = cs.length; i < len; i++){
5119 if(!c.getAttribute("_nodup") != d){
5120 c.setAttribute("_nodup", d);
5124 for(var i = 0, len = cs.length; i < len; i++){
5125 cs[i].removeAttribute("_nodup");
5134 var len = cs.length, c, i, r = cs, cj, ri = -1;
5135 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5138 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5139 return nodupIEXml(cs);
5143 for(i = 1; c = cs[i]; i++){
5148 for(var j = 0; j < i; j++){
5151 for(j = i+1; cj = cs[j]; j++){
5163 function quickDiffIEXml(c1, c2){
5165 for(var i = 0, len = c1.length; i < len; i++){
5166 c1[i].setAttribute("_qdiff", d);
5169 for(var i = 0, len = c2.length; i < len; i++){
5170 if(c2[i].getAttribute("_qdiff") != d){
5171 r[r.length] = c2[i];
5174 for(var i = 0, len = c1.length; i < len; i++){
5175 c1[i].removeAttribute("_qdiff");
5180 function quickDiff(c1, c2){
5181 var len1 = c1.length;
5185 if(isIE && c1[0].selectSingleNode){
5186 return quickDiffIEXml(c1, c2);
5189 for(var i = 0; i < len1; i++){
5193 for(var i = 0, len = c2.length; i < len; i++){
5194 if(c2[i]._qdiff != d){
5195 r[r.length] = c2[i];
5201 function quickId(ns, mode, root, id){
5203 var d = root.ownerDocument || root;
5204 return d.getElementById(id);
5206 ns = getNodes(ns, mode, "*");
5207 return byId(ns, null, id);
5211 getStyle : function(el, name){
5212 return Roo.fly(el).getStyle(name);
5215 * Compiles a selector/xpath query into a reusable function. The returned function
5216 * takes one parameter "root" (optional), which is the context node from where the query should start.
5217 * @param {String} selector The selector/xpath query
5218 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5219 * @return {Function}
5221 compile : function(path, type){
5222 type = type || "select";
5224 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5225 var q = path, mode, lq;
5226 var tk = Roo.DomQuery.matchers;
5227 var tklen = tk.length;
5230 // accept leading mode switch
5231 var lmode = q.match(modeRe);
5232 if(lmode && lmode[1]){
5233 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5234 q = q.replace(lmode[1], "");
5236 // strip leading slashes
5237 while(path.substr(0, 1)=="/"){
5238 path = path.substr(1);
5241 while(q && lq != q){
5243 var tm = q.match(tagTokenRe);
5244 if(type == "select"){
5247 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5249 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5251 q = q.replace(tm[0], "");
5252 }else if(q.substr(0, 1) != '@'){
5253 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5258 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5260 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5262 q = q.replace(tm[0], "");
5265 while(!(mm = q.match(modeRe))){
5266 var matched = false;
5267 for(var j = 0; j < tklen; j++){
5269 var m = q.match(t.re);
5271 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5274 q = q.replace(m[0], "");
5279 // prevent infinite loop on bad selector
5281 throw 'Error parsing selector, parsing failed at "' + q + '"';
5285 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5286 q = q.replace(mm[1], "");
5289 fn[fn.length] = "return nodup(n);\n}";
5292 * list of variables that need from compression as they are used by eval.
5302 * eval:var:byClassName
5304 * eval:var:byAttribute
5305 * eval:var:attrValue
5313 * Selects a group of elements.
5314 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5315 * @param {Node} root (optional) The start of the query (defaults to document).
5318 select : function(path, root, type){
5319 if(!root || root == document){
5322 if(typeof root == "string"){
5323 root = document.getElementById(root);
5325 var paths = path.split(",");
5327 for(var i = 0, len = paths.length; i < len; i++){
5328 var p = paths[i].replace(trimRe, "");
5330 cache[p] = Roo.DomQuery.compile(p);
5332 throw p + " is not a valid selector";
5335 var result = cache[p](root);
5336 if(result && result != document){
5337 results = results.concat(result);
5340 if(paths.length > 1){
5341 return nodup(results);
5347 * Selects a single element.
5348 * @param {String} selector The selector/xpath query
5349 * @param {Node} root (optional) The start of the query (defaults to document).
5352 selectNode : function(path, root){
5353 return Roo.DomQuery.select(path, root)[0];
5357 * Selects the value of a node, optionally replacing null with the defaultValue.
5358 * @param {String} selector The selector/xpath query
5359 * @param {Node} root (optional) The start of the query (defaults to document).
5360 * @param {String} defaultValue
5362 selectValue : function(path, root, defaultValue){
5363 path = path.replace(trimRe, "");
5364 if(!valueCache[path]){
5365 valueCache[path] = Roo.DomQuery.compile(path, "select");
5367 var n = valueCache[path](root);
5368 n = n[0] ? n[0] : n;
5369 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5370 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5374 * Selects the value of a node, parsing integers and floats.
5375 * @param {String} selector The selector/xpath query
5376 * @param {Node} root (optional) The start of the query (defaults to document).
5377 * @param {Number} defaultValue
5380 selectNumber : function(path, root, defaultValue){
5381 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5382 return parseFloat(v);
5386 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5387 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5388 * @param {String} selector The simple selector to test
5391 is : function(el, ss){
5392 if(typeof el == "string"){
5393 el = document.getElementById(el);
5395 var isArray = (el instanceof Array);
5396 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5397 return isArray ? (result.length == el.length) : (result.length > 0);
5401 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5402 * @param {Array} el An array of elements to filter
5403 * @param {String} selector The simple selector to test
5404 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5405 * the selector instead of the ones that match
5408 filter : function(els, ss, nonMatches){
5409 ss = ss.replace(trimRe, "");
5410 if(!simpleCache[ss]){
5411 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5413 var result = simpleCache[ss](els);
5414 return nonMatches ? quickDiff(result, els) : result;
5418 * Collection of matching regular expressions and code snippets.
5422 select: 'n = byClassName(n, null, " {1} ");'
5424 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5425 select: 'n = byPseudo(n, "{1}", "{2}");'
5427 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5428 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5431 select: 'n = byId(n, null, "{1}");'
5434 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5439 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5440 * 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, > <.
5443 "=" : function(a, v){
5446 "!=" : function(a, v){
5449 "^=" : function(a, v){
5450 return a && a.substr(0, v.length) == v;
5452 "$=" : function(a, v){
5453 return a && a.substr(a.length-v.length) == v;
5455 "*=" : function(a, v){
5456 return a && a.indexOf(v) !== -1;
5458 "%=" : function(a, v){
5459 return (a % v) == 0;
5461 "|=" : function(a, v){
5462 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5464 "~=" : function(a, v){
5465 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5470 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5471 * and the argument (if any) supplied in the selector.
5474 "first-child" : function(c){
5475 var r = [], ri = -1, n;
5476 for(var i = 0, ci; ci = n = c[i]; i++){
5477 while((n = n.previousSibling) && n.nodeType != 1);
5485 "last-child" : function(c){
5486 var r = [], ri = -1, n;
5487 for(var i = 0, ci; ci = n = c[i]; i++){
5488 while((n = n.nextSibling) && n.nodeType != 1);
5496 "nth-child" : function(c, a) {
5497 var r = [], ri = -1;
5498 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5499 var f = (m[1] || 1) - 0, l = m[2] - 0;
5500 for(var i = 0, n; n = c[i]; i++){
5501 var pn = n.parentNode;
5502 if (batch != pn._batch) {
5504 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5505 if(cn.nodeType == 1){
5512 if (l == 0 || n.nodeIndex == l){
5515 } else if ((n.nodeIndex + l) % f == 0){
5523 "only-child" : function(c){
5524 var r = [], ri = -1;;
5525 for(var i = 0, ci; ci = c[i]; i++){
5526 if(!prev(ci) && !next(ci)){
5533 "empty" : function(c){
5534 var r = [], ri = -1;
5535 for(var i = 0, ci; ci = c[i]; i++){
5536 var cns = ci.childNodes, j = 0, cn, empty = true;
5539 if(cn.nodeType == 1 || cn.nodeType == 3){
5551 "contains" : function(c, v){
5552 var r = [], ri = -1;
5553 for(var i = 0, ci; ci = c[i]; i++){
5554 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5561 "nodeValue" : function(c, v){
5562 var r = [], ri = -1;
5563 for(var i = 0, ci; ci = c[i]; i++){
5564 if(ci.firstChild && ci.firstChild.nodeValue == v){
5571 "checked" : function(c){
5572 var r = [], ri = -1;
5573 for(var i = 0, ci; ci = c[i]; i++){
5574 if(ci.checked == true){
5581 "not" : function(c, ss){
5582 return Roo.DomQuery.filter(c, ss, true);
5585 "odd" : function(c){
5586 return this["nth-child"](c, "odd");
5589 "even" : function(c){
5590 return this["nth-child"](c, "even");
5593 "nth" : function(c, a){
5594 return c[a-1] || [];
5597 "first" : function(c){
5601 "last" : function(c){
5602 return c[c.length-1] || [];
5605 "has" : function(c, ss){
5606 var s = Roo.DomQuery.select;
5607 var r = [], ri = -1;
5608 for(var i = 0, ci; ci = c[i]; i++){
5609 if(s(ss, ci).length > 0){
5616 "next" : function(c, ss){
5617 var is = Roo.DomQuery.is;
5618 var r = [], ri = -1;
5619 for(var i = 0, ci; ci = c[i]; i++){
5628 "prev" : function(c, ss){
5629 var is = Roo.DomQuery.is;
5630 var r = [], ri = -1;
5631 for(var i = 0, ci; ci = c[i]; i++){
5644 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5645 * @param {String} path The selector/xpath query
5646 * @param {Node} root (optional) The start of the query (defaults to document).
5651 Roo.query = Roo.DomQuery.select;
5654 * Ext JS Library 1.1.1
5655 * Copyright(c) 2006-2007, Ext JS, LLC.
5657 * Originally Released Under LGPL - original licence link has changed is not relivant.
5660 * <script type="text/javascript">
5664 * @class Roo.util.Observable
5665 * Base class that provides a common interface for publishing events. Subclasses are expected to
5666 * to have a property "events" with all the events defined.<br>
5669 Employee = function(name){
5676 Roo.extend(Employee, Roo.util.Observable);
5678 * @param {Object} config properties to use (incuding events / listeners)
5681 Roo.util.Observable = function(cfg){
5684 this.addEvents(cfg.events || {});
5686 delete cfg.events; // make sure
5689 Roo.apply(this, cfg);
5692 this.on(this.listeners);
5693 delete this.listeners;
5696 Roo.util.Observable.prototype = {
5698 * @cfg {Object} listeners list of events and functions to call for this object,
5702 'click' : function(e) {
5712 * Fires the specified event with the passed parameters (minus the event name).
5713 * @param {String} eventName
5714 * @param {Object...} args Variable number of parameters are passed to handlers
5715 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5717 fireEvent : function(){
5718 var ce = this.events[arguments[0].toLowerCase()];
5719 if(typeof ce == "object"){
5720 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5727 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5730 * Appends an event handler to this component
5731 * @param {String} eventName The type of event to listen for
5732 * @param {Function} handler The method the event invokes
5733 * @param {Object} scope (optional) The scope in which to execute the handler
5734 * function. The handler function's "this" context.
5735 * @param {Object} options (optional) An object containing handler configuration
5736 * properties. This may contain any of the following properties:<ul>
5737 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5738 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5739 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5740 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5741 * by the specified number of milliseconds. If the event fires again within that time, the original
5742 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5745 * <b>Combining Options</b><br>
5746 * Using the options argument, it is possible to combine different types of listeners:<br>
5748 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5750 el.on('click', this.onClick, this, {
5757 * <b>Attaching multiple handlers in 1 call</b><br>
5758 * The method also allows for a single argument to be passed which is a config object containing properties
5759 * which specify multiple handlers.
5768 fn: this.onMouseOver,
5772 fn: this.onMouseOut,
5778 * Or a shorthand syntax which passes the same scope object to all handlers:
5781 'click': this.onClick,
5782 'mouseover': this.onMouseOver,
5783 'mouseout': this.onMouseOut,
5788 addListener : function(eventName, fn, scope, o){
5789 if(typeof eventName == "object"){
5792 if(this.filterOptRe.test(e)){
5795 if(typeof o[e] == "function"){
5797 this.addListener(e, o[e], o.scope, o);
5799 // individual options
5800 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5805 o = (!o || typeof o == "boolean") ? {} : o;
5806 eventName = eventName.toLowerCase();
5807 var ce = this.events[eventName] || true;
5808 if(typeof ce == "boolean"){
5809 ce = new Roo.util.Event(this, eventName);
5810 this.events[eventName] = ce;
5812 ce.addListener(fn, scope, o);
5816 * Removes a listener
5817 * @param {String} eventName The type of event to listen for
5818 * @param {Function} handler The handler to remove
5819 * @param {Object} scope (optional) The scope (this object) for the handler
5821 removeListener : function(eventName, fn, scope){
5822 var ce = this.events[eventName.toLowerCase()];
5823 if(typeof ce == "object"){
5824 ce.removeListener(fn, scope);
5829 * Removes all listeners for this object
5831 purgeListeners : function(){
5832 for(var evt in this.events){
5833 if(typeof this.events[evt] == "object"){
5834 this.events[evt].clearListeners();
5839 relayEvents : function(o, events){
5840 var createHandler = function(ename){
5842 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5845 for(var i = 0, len = events.length; i < len; i++){
5846 var ename = events[i];
5847 if(!this.events[ename]){ this.events[ename] = true; };
5848 o.on(ename, createHandler(ename), this);
5853 * Used to define events on this Observable
5854 * @param {Object} object The object with the events defined
5856 addEvents : function(o){
5860 Roo.applyIf(this.events, o);
5864 * Checks to see if this object has any listeners for a specified event
5865 * @param {String} eventName The name of the event to check for
5866 * @return {Boolean} True if the event is being listened for, else false
5868 hasListener : function(eventName){
5869 var e = this.events[eventName];
5870 return typeof e == "object" && e.listeners.length > 0;
5874 * Appends an event handler to this element (shorthand for addListener)
5875 * @param {String} eventName The type of event to listen for
5876 * @param {Function} handler The method the event invokes
5877 * @param {Object} scope (optional) The scope in which to execute the handler
5878 * function. The handler function's "this" context.
5879 * @param {Object} options (optional)
5882 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5884 * Removes a listener (shorthand for removeListener)
5885 * @param {String} eventName The type of event to listen for
5886 * @param {Function} handler The handler to remove
5887 * @param {Object} scope (optional) The scope (this object) for the handler
5890 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5893 * Starts capture on the specified Observable. All events will be passed
5894 * to the supplied function with the event name + standard signature of the event
5895 * <b>before</b> the event is fired. If the supplied function returns false,
5896 * the event will not fire.
5897 * @param {Observable} o The Observable to capture
5898 * @param {Function} fn The function to call
5899 * @param {Object} scope (optional) The scope (this object) for the fn
5902 Roo.util.Observable.capture = function(o, fn, scope){
5903 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5907 * Removes <b>all</b> added captures from the Observable.
5908 * @param {Observable} o The Observable to release
5911 Roo.util.Observable.releaseCapture = function(o){
5912 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5917 var createBuffered = function(h, o, scope){
5918 var task = new Roo.util.DelayedTask();
5920 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5924 var createSingle = function(h, e, fn, scope){
5926 e.removeListener(fn, scope);
5927 return h.apply(scope, arguments);
5931 var createDelayed = function(h, o, scope){
5933 var args = Array.prototype.slice.call(arguments, 0);
5934 setTimeout(function(){
5935 h.apply(scope, args);
5940 Roo.util.Event = function(obj, name){
5943 this.listeners = [];
5946 Roo.util.Event.prototype = {
5947 addListener : function(fn, scope, options){
5948 var o = options || {};
5949 scope = scope || this.obj;
5950 if(!this.isListening(fn, scope)){
5951 var l = {fn: fn, scope: scope, options: o};
5954 h = createDelayed(h, o, scope);
5957 h = createSingle(h, this, fn, scope);
5960 h = createBuffered(h, o, scope);
5963 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5964 this.listeners.push(l);
5966 this.listeners = this.listeners.slice(0);
5967 this.listeners.push(l);
5972 findListener : function(fn, scope){
5973 scope = scope || this.obj;
5974 var ls = this.listeners;
5975 for(var i = 0, len = ls.length; i < len; i++){
5977 if(l.fn == fn && l.scope == scope){
5984 isListening : function(fn, scope){
5985 return this.findListener(fn, scope) != -1;
5988 removeListener : function(fn, scope){
5990 if((index = this.findListener(fn, scope)) != -1){
5992 this.listeners.splice(index, 1);
5994 this.listeners = this.listeners.slice(0);
5995 this.listeners.splice(index, 1);
6002 clearListeners : function(){
6003 this.listeners = [];
6007 var ls = this.listeners, scope, len = ls.length;
6010 var args = Array.prototype.slice.call(arguments, 0);
6011 for(var i = 0; i < len; i++){
6013 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6014 this.firing = false;
6018 this.firing = false;
6025 * Ext JS Library 1.1.1
6026 * Copyright(c) 2006-2007, Ext JS, LLC.
6028 * Originally Released Under LGPL - original licence link has changed is not relivant.
6031 * <script type="text/javascript">
6035 * @class Roo.EventManager
6036 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6037 * several useful events directly.
6038 * See {@link Roo.EventObject} for more details on normalized event objects.
6041 Roo.EventManager = function(){
6042 var docReadyEvent, docReadyProcId, docReadyState = false;
6043 var resizeEvent, resizeTask, textEvent, textSize;
6044 var E = Roo.lib.Event;
6045 var D = Roo.lib.Dom;
6048 var fireDocReady = function(){
6050 docReadyState = true;
6053 clearInterval(docReadyProcId);
6055 if(Roo.isGecko || Roo.isOpera) {
6056 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6059 var defer = document.getElementById("ie-deferred-loader");
6061 defer.onreadystatechange = null;
6062 defer.parentNode.removeChild(defer);
6066 docReadyEvent.fire();
6067 docReadyEvent.clearListeners();
6072 var initDocReady = function(){
6073 docReadyEvent = new Roo.util.Event();
6074 if(Roo.isGecko || Roo.isOpera) {
6075 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6077 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6078 var defer = document.getElementById("ie-deferred-loader");
6079 defer.onreadystatechange = function(){
6080 if(this.readyState == "complete"){
6084 }else if(Roo.isSafari){
6085 docReadyProcId = setInterval(function(){
6086 var rs = document.readyState;
6087 if(rs == "complete") {
6092 // no matter what, make sure it fires on load
6093 E.on(window, "load", fireDocReady);
6096 var createBuffered = function(h, o){
6097 var task = new Roo.util.DelayedTask(h);
6099 // create new event object impl so new events don't wipe out properties
6100 e = new Roo.EventObjectImpl(e);
6101 task.delay(o.buffer, h, null, [e]);
6105 var createSingle = function(h, el, ename, fn){
6107 Roo.EventManager.removeListener(el, ename, fn);
6112 var createDelayed = function(h, o){
6114 // create new event object impl so new events don't wipe out properties
6115 e = new Roo.EventObjectImpl(e);
6116 setTimeout(function(){
6122 var listen = function(element, ename, opt, fn, scope){
6123 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6124 fn = fn || o.fn; scope = scope || o.scope;
6125 var el = Roo.getDom(element);
6127 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6129 var h = function(e){
6130 e = Roo.EventObject.setEvent(e);
6133 t = e.getTarget(o.delegate, el);
6140 if(o.stopEvent === true){
6143 if(o.preventDefault === true){
6146 if(o.stopPropagation === true){
6147 e.stopPropagation();
6150 if(o.normalized === false){
6154 fn.call(scope || el, e, t, o);
6157 h = createDelayed(h, o);
6160 h = createSingle(h, el, ename, fn);
6163 h = createBuffered(h, o);
6165 fn._handlers = fn._handlers || [];
6166 fn._handlers.push([Roo.id(el), ename, h]);
6169 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6170 el.addEventListener("DOMMouseScroll", h, false);
6171 E.on(window, 'unload', function(){
6172 el.removeEventListener("DOMMouseScroll", h, false);
6175 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6176 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6181 var stopListening = function(el, ename, fn){
6182 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6184 for(var i = 0, len = hds.length; i < len; i++){
6186 if(h[0] == id && h[1] == ename){
6193 E.un(el, ename, hd);
6194 el = Roo.getDom(el);
6195 if(ename == "mousewheel" && el.addEventListener){
6196 el.removeEventListener("DOMMouseScroll", hd, false);
6198 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6199 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6203 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6210 * @scope Roo.EventManager
6215 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6216 * object with a Roo.EventObject
6217 * @param {Function} fn The method the event invokes
6218 * @param {Object} scope An object that becomes the scope of the handler
6219 * @param {boolean} override If true, the obj passed in becomes
6220 * the execution scope of the listener
6221 * @return {Function} The wrapped function
6224 wrap : function(fn, scope, override){
6226 Roo.EventObject.setEvent(e);
6227 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6232 * Appends an event handler to an element (shorthand for addListener)
6233 * @param {String/HTMLElement} element The html element or id to assign the
6234 * @param {String} eventName The type of event to listen for
6235 * @param {Function} handler The method the event invokes
6236 * @param {Object} scope (optional) The scope in which to execute the handler
6237 * function. The handler function's "this" context.
6238 * @param {Object} options (optional) An object containing handler configuration
6239 * properties. This may contain any of the following properties:<ul>
6240 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6241 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6242 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6243 * <li>preventDefault {Boolean} True to prevent the default action</li>
6244 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6245 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6246 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6247 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6248 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6249 * by the specified number of milliseconds. If the event fires again within that time, the original
6250 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6253 * <b>Combining Options</b><br>
6254 * Using the options argument, it is possible to combine different types of listeners:<br>
6256 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6258 el.on('click', this.onClick, this, {
6265 * <b>Attaching multiple handlers in 1 call</b><br>
6266 * The method also allows for a single argument to be passed which is a config object containing properties
6267 * which specify multiple handlers.
6277 fn: this.onMouseOver
6286 * Or a shorthand syntax:<br>
6289 'click' : this.onClick,
6290 'mouseover' : this.onMouseOver,
6291 'mouseout' : this.onMouseOut
6295 addListener : function(element, eventName, fn, scope, options){
6296 if(typeof eventName == "object"){
6302 if(typeof o[e] == "function"){
6304 listen(element, e, o, o[e], o.scope);
6306 // individual options
6307 listen(element, e, o[e]);
6312 return listen(element, eventName, options, fn, scope);
6316 * Removes an event handler
6318 * @param {String/HTMLElement} element The id or html element to remove the
6320 * @param {String} eventName The type of event
6321 * @param {Function} fn
6322 * @return {Boolean} True if a listener was actually removed
6324 removeListener : function(element, eventName, fn){
6325 return stopListening(element, eventName, fn);
6329 * Fires when the document is ready (before onload and before images are loaded). Can be
6330 * accessed shorthanded Roo.onReady().
6331 * @param {Function} fn The method the event invokes
6332 * @param {Object} scope An object that becomes the scope of the handler
6333 * @param {boolean} options
6335 onDocumentReady : function(fn, scope, options){
6336 if(docReadyState){ // if it already fired
6337 docReadyEvent.addListener(fn, scope, options);
6338 docReadyEvent.fire();
6339 docReadyEvent.clearListeners();
6345 docReadyEvent.addListener(fn, scope, options);
6349 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6350 * @param {Function} fn The method the event invokes
6351 * @param {Object} scope An object that becomes the scope of the handler
6352 * @param {boolean} options
6354 onWindowResize : function(fn, scope, options){
6356 resizeEvent = new Roo.util.Event();
6357 resizeTask = new Roo.util.DelayedTask(function(){
6358 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6360 E.on(window, "resize", function(){
6362 resizeTask.delay(50);
6364 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6368 resizeEvent.addListener(fn, scope, options);
6372 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6373 * @param {Function} fn The method the event invokes
6374 * @param {Object} scope An object that becomes the scope of the handler
6375 * @param {boolean} options
6377 onTextResize : function(fn, scope, options){
6379 textEvent = new Roo.util.Event();
6380 var textEl = new Roo.Element(document.createElement('div'));
6381 textEl.dom.className = 'x-text-resize';
6382 textEl.dom.innerHTML = 'X';
6383 textEl.appendTo(document.body);
6384 textSize = textEl.dom.offsetHeight;
6385 setInterval(function(){
6386 if(textEl.dom.offsetHeight != textSize){
6387 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6389 }, this.textResizeInterval);
6391 textEvent.addListener(fn, scope, options);
6395 * Removes the passed window resize listener.
6396 * @param {Function} fn The method the event invokes
6397 * @param {Object} scope The scope of handler
6399 removeResizeListener : function(fn, scope){
6401 resizeEvent.removeListener(fn, scope);
6406 fireResize : function(){
6408 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6412 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6416 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6418 textResizeInterval : 50
6423 * @scopeAlias pub=Roo.EventManager
6427 * Appends an event handler to an element (shorthand for addListener)
6428 * @param {String/HTMLElement} element The html element or id to assign the
6429 * @param {String} eventName The type of event to listen for
6430 * @param {Function} handler The method the event invokes
6431 * @param {Object} scope (optional) The scope in which to execute the handler
6432 * function. The handler function's "this" context.
6433 * @param {Object} options (optional) An object containing handler configuration
6434 * properties. This may contain any of the following properties:<ul>
6435 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6436 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6437 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6438 * <li>preventDefault {Boolean} True to prevent the default action</li>
6439 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6440 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6441 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6442 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6443 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6444 * by the specified number of milliseconds. If the event fires again within that time, the original
6445 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6448 * <b>Combining Options</b><br>
6449 * Using the options argument, it is possible to combine different types of listeners:<br>
6451 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6453 el.on('click', this.onClick, this, {
6460 * <b>Attaching multiple handlers in 1 call</b><br>
6461 * The method also allows for a single argument to be passed which is a config object containing properties
6462 * which specify multiple handlers.
6472 fn: this.onMouseOver
6481 * Or a shorthand syntax:<br>
6484 'click' : this.onClick,
6485 'mouseover' : this.onMouseOver,
6486 'mouseout' : this.onMouseOut
6490 pub.on = pub.addListener;
6491 pub.un = pub.removeListener;
6493 pub.stoppedMouseDownEvent = new Roo.util.Event();
6497 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6498 * @param {Function} fn The method the event invokes
6499 * @param {Object} scope An object that becomes the scope of the handler
6500 * @param {boolean} override If true, the obj passed in becomes
6501 * the execution scope of the listener
6505 Roo.onReady = Roo.EventManager.onDocumentReady;
6507 Roo.onReady(function(){
6508 var bd = Roo.get(document.body);
6513 : Roo.isGecko ? "roo-gecko"
6514 : Roo.isOpera ? "roo-opera"
6515 : Roo.isSafari ? "roo-safari" : ""];
6518 cls.push("roo-mac");
6521 cls.push("roo-linux");
6523 if(Roo.isBorderBox){
6524 cls.push('roo-border-box');
6526 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6527 var p = bd.dom.parentNode;
6529 p.className += ' roo-strict';
6532 bd.addClass(cls.join(' '));
6536 * @class Roo.EventObject
6537 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6538 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6541 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6543 var target = e.getTarget();
6546 var myDiv = Roo.get("myDiv");
6547 myDiv.on("click", handleClick);
6549 Roo.EventManager.on("myDiv", 'click', handleClick);
6550 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6554 Roo.EventObject = function(){
6556 var E = Roo.lib.Event;
6558 // safari keypress events for special keys return bad keycodes
6561 63235 : 39, // right
6564 63276 : 33, // page up
6565 63277 : 34, // page down
6566 63272 : 46, // delete
6571 // normalize button clicks
6572 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6573 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6575 Roo.EventObjectImpl = function(e){
6577 this.setEvent(e.browserEvent || e);
6580 Roo.EventObjectImpl.prototype = {
6582 * Used to fix doc tools.
6583 * @scope Roo.EventObject.prototype
6589 /** The normal browser event */
6590 browserEvent : null,
6591 /** The button pressed in a mouse event */
6593 /** True if the shift key was down during the event */
6595 /** True if the control key was down during the event */
6597 /** True if the alt key was down during the event */
6656 setEvent : function(e){
6657 if(e == this || (e && e.browserEvent)){ // already wrapped
6660 this.browserEvent = e;
6662 // normalize buttons
6663 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6664 if(e.type == 'click' && this.button == -1){
6668 this.shiftKey = e.shiftKey;
6669 // mac metaKey behaves like ctrlKey
6670 this.ctrlKey = e.ctrlKey || e.metaKey;
6671 this.altKey = e.altKey;
6672 // in getKey these will be normalized for the mac
6673 this.keyCode = e.keyCode;
6674 // keyup warnings on firefox.
6675 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6676 // cache the target for the delayed and or buffered events
6677 this.target = E.getTarget(e);
6679 this.xy = E.getXY(e);
6682 this.shiftKey = false;
6683 this.ctrlKey = false;
6684 this.altKey = false;
6694 * Stop the event (preventDefault and stopPropagation)
6696 stopEvent : function(){
6697 if(this.browserEvent){
6698 if(this.browserEvent.type == 'mousedown'){
6699 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6701 E.stopEvent(this.browserEvent);
6706 * Prevents the browsers default handling of the event.
6708 preventDefault : function(){
6709 if(this.browserEvent){
6710 E.preventDefault(this.browserEvent);
6715 isNavKeyPress : function(){
6716 var k = this.keyCode;
6717 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6718 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6721 isSpecialKey : function(){
6722 var k = this.keyCode;
6723 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6724 (k == 16) || (k == 17) ||
6725 (k >= 18 && k <= 20) ||
6726 (k >= 33 && k <= 35) ||
6727 (k >= 36 && k <= 39) ||
6728 (k >= 44 && k <= 45);
6731 * Cancels bubbling of the event.
6733 stopPropagation : function(){
6734 if(this.browserEvent){
6735 if(this.type == 'mousedown'){
6736 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6738 E.stopPropagation(this.browserEvent);
6743 * Gets the key code for the event.
6746 getCharCode : function(){
6747 return this.charCode || this.keyCode;
6751 * Returns a normalized keyCode for the event.
6752 * @return {Number} The key code
6754 getKey : function(){
6755 var k = this.keyCode || this.charCode;
6756 return Roo.isSafari ? (safariKeys[k] || k) : k;
6760 * Gets the x coordinate of the event.
6763 getPageX : function(){
6768 * Gets the y coordinate of the event.
6771 getPageY : function(){
6776 * Gets the time of the event.
6779 getTime : function(){
6780 if(this.browserEvent){
6781 return E.getTime(this.browserEvent);
6787 * Gets the page coordinates of the event.
6788 * @return {Array} The xy values like [x, y]
6795 * Gets the target for the event.
6796 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6797 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6798 search as a number or element (defaults to 10 || document.body)
6799 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6800 * @return {HTMLelement}
6802 getTarget : function(selector, maxDepth, returnEl){
6803 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6806 * Gets the related target.
6807 * @return {HTMLElement}
6809 getRelatedTarget : function(){
6810 if(this.browserEvent){
6811 return E.getRelatedTarget(this.browserEvent);
6817 * Normalizes mouse wheel delta across browsers
6818 * @return {Number} The delta
6820 getWheelDelta : function(){
6821 var e = this.browserEvent;
6823 if(e.wheelDelta){ /* IE/Opera. */
6824 delta = e.wheelDelta/120;
6825 }else if(e.detail){ /* Mozilla case. */
6826 delta = -e.detail/3;
6832 * Returns true if the control, meta, shift or alt key was pressed during this event.
6835 hasModifier : function(){
6836 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6840 * Returns true if the target of this event equals el or is a child of el
6841 * @param {String/HTMLElement/Element} el
6842 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6845 within : function(el, related){
6846 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6847 return t && Roo.fly(el).contains(t);
6850 getPoint : function(){
6851 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6855 return new Roo.EventObjectImpl();
6860 * Ext JS Library 1.1.1
6861 * Copyright(c) 2006-2007, Ext JS, LLC.
6863 * Originally Released Under LGPL - original licence link has changed is not relivant.
6866 * <script type="text/javascript">
6870 // was in Composite Element!??!?!
6873 var D = Roo.lib.Dom;
6874 var E = Roo.lib.Event;
6875 var A = Roo.lib.Anim;
6877 // local style camelizing for speed
6879 var camelRe = /(-[a-z])/gi;
6880 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6881 var view = document.defaultView;
6884 * @class Roo.Element
6885 * Represents an Element in the DOM.<br><br>
6888 var el = Roo.get("my-div");
6891 var el = getEl("my-div");
6893 // or with a DOM element
6894 var el = Roo.get(myDivElement);
6896 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6897 * each call instead of constructing a new one.<br><br>
6898 * <b>Animations</b><br />
6899 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6900 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6902 Option Default Description
6903 --------- -------- ---------------------------------------------
6904 duration .35 The duration of the animation in seconds
6905 easing easeOut The YUI easing method
6906 callback none A function to execute when the anim completes
6907 scope this The scope (this) of the callback function
6909 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6910 * manipulate the animation. Here's an example:
6912 var el = Roo.get("my-div");
6917 // default animation
6918 el.setWidth(100, true);
6920 // animation with some options set
6927 // using the "anim" property to get the Anim object
6933 el.setWidth(100, opt);
6935 if(opt.anim.isAnimated()){
6939 * <b> Composite (Collections of) Elements</b><br />
6940 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6941 * @constructor Create a new Element directly.
6942 * @param {String/HTMLElement} element
6943 * @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).
6945 Roo.Element = function(element, forceNew){
6946 var dom = typeof element == "string" ?
6947 document.getElementById(element) : element;
6948 if(!dom){ // invalid id/element
6952 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6953 return Roo.Element.cache[id];
6963 * The DOM element ID
6966 this.id = id || Roo.id(dom);
6969 var El = Roo.Element;
6973 * The element's default display mode (defaults to "")
6976 originalDisplay : "",
6980 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6985 * Sets the element's visibility mode. When setVisible() is called it
6986 * will use this to determine whether to set the visibility or the display property.
6987 * @param visMode Element.VISIBILITY or Element.DISPLAY
6988 * @return {Roo.Element} this
6990 setVisibilityMode : function(visMode){
6991 this.visibilityMode = visMode;
6995 * Convenience method for setVisibilityMode(Element.DISPLAY)
6996 * @param {String} display (optional) What to set display to when visible
6997 * @return {Roo.Element} this
6999 enableDisplayMode : function(display){
7000 this.setVisibilityMode(El.DISPLAY);
7001 if(typeof display != "undefined") this.originalDisplay = display;
7006 * 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)
7007 * @param {String} selector The simple selector to test
7008 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7009 search as a number or element (defaults to 10 || document.body)
7010 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7011 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7013 findParent : function(simpleSelector, maxDepth, returnEl){
7014 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7015 maxDepth = maxDepth || 50;
7016 if(typeof maxDepth != "number"){
7017 stopEl = Roo.getDom(maxDepth);
7020 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7021 if(dq.is(p, simpleSelector)){
7022 return returnEl ? Roo.get(p) : p;
7032 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7033 * @param {String} selector The simple selector to test
7034 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7035 search as a number or element (defaults to 10 || document.body)
7036 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7037 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7039 findParentNode : function(simpleSelector, maxDepth, returnEl){
7040 var p = Roo.fly(this.dom.parentNode, '_internal');
7041 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7045 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7046 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7047 * @param {String} selector The simple selector to test
7048 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7049 search as a number or element (defaults to 10 || document.body)
7050 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7052 up : function(simpleSelector, maxDepth){
7053 return this.findParentNode(simpleSelector, maxDepth, true);
7059 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7060 * @param {String} selector The simple selector to test
7061 * @return {Boolean} True if this element matches the selector, else false
7063 is : function(simpleSelector){
7064 return Roo.DomQuery.is(this.dom, simpleSelector);
7068 * Perform animation on this element.
7069 * @param {Object} args The YUI animation control args
7070 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7071 * @param {Function} onComplete (optional) Function to call when animation completes
7072 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7073 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7074 * @return {Roo.Element} this
7076 animate : function(args, duration, onComplete, easing, animType){
7077 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7082 * @private Internal animation call
7084 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7085 animType = animType || 'run';
7087 var anim = Roo.lib.Anim[animType](
7089 (opt.duration || defaultDur) || .35,
7090 (opt.easing || defaultEase) || 'easeOut',
7092 Roo.callback(cb, this);
7093 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7101 // private legacy anim prep
7102 preanim : function(a, i){
7103 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7107 * Removes worthless text nodes
7108 * @param {Boolean} forceReclean (optional) By default the element
7109 * keeps track if it has been cleaned already so
7110 * you can call this over and over. However, if you update the element and
7111 * need to force a reclean, you can pass true.
7113 clean : function(forceReclean){
7114 if(this.isCleaned && forceReclean !== true){
7118 var d = this.dom, n = d.firstChild, ni = -1;
7120 var nx = n.nextSibling;
7121 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7128 this.isCleaned = true;
7133 calcOffsetsTo : function(el){
7136 var restorePos = false;
7137 if(el.getStyle('position') == 'static'){
7138 el.position('relative');
7143 while(op && op != d && op.tagName != 'HTML'){
7146 op = op.offsetParent;
7149 el.position('static');
7155 * Scrolls this element into view within the passed container.
7156 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7157 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7158 * @return {Roo.Element} this
7160 scrollIntoView : function(container, hscroll){
7161 var c = Roo.getDom(container) || document.body;
7164 var o = this.calcOffsetsTo(c),
7167 b = t+el.offsetHeight,
7168 r = l+el.offsetWidth;
7170 var ch = c.clientHeight;
7171 var ct = parseInt(c.scrollTop, 10);
7172 var cl = parseInt(c.scrollLeft, 10);
7174 var cr = cl + c.clientWidth;
7182 if(hscroll !== false){
7186 c.scrollLeft = r-c.clientWidth;
7193 scrollChildIntoView : function(child, hscroll){
7194 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7198 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7199 * the new height may not be available immediately.
7200 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7201 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7202 * @param {Function} onComplete (optional) Function to call when animation completes
7203 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7204 * @return {Roo.Element} this
7206 autoHeight : function(animate, duration, onComplete, easing){
7207 var oldHeight = this.getHeight();
7209 this.setHeight(1); // force clipping
7210 setTimeout(function(){
7211 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7213 this.setHeight(height);
7215 if(typeof onComplete == "function"){
7219 this.setHeight(oldHeight); // restore original height
7220 this.setHeight(height, animate, duration, function(){
7222 if(typeof onComplete == "function") onComplete();
7223 }.createDelegate(this), easing);
7225 }.createDelegate(this), 0);
7230 * Returns true if this element is an ancestor of the passed element
7231 * @param {HTMLElement/String} el The element to check
7232 * @return {Boolean} True if this element is an ancestor of el, else false
7234 contains : function(el){
7235 if(!el){return false;}
7236 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7240 * Checks whether the element is currently visible using both visibility and display properties.
7241 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7242 * @return {Boolean} True if the element is currently visible, else false
7244 isVisible : function(deep) {
7245 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7246 if(deep !== true || !vis){
7249 var p = this.dom.parentNode;
7250 while(p && p.tagName.toLowerCase() != "body"){
7251 if(!Roo.fly(p, '_isVisible').isVisible()){
7260 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7261 * @param {String} selector The CSS selector
7262 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7263 * @return {CompositeElement/CompositeElementLite} The composite element
7265 select : function(selector, unique){
7266 return El.select(selector, unique, this.dom);
7270 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7271 * @param {String} selector The CSS selector
7272 * @return {Array} An array of the matched nodes
7274 query : function(selector, unique){
7275 return Roo.DomQuery.select(selector, this.dom);
7279 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7280 * @param {String} selector The CSS selector
7281 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7282 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7284 child : function(selector, returnDom){
7285 var n = Roo.DomQuery.selectNode(selector, this.dom);
7286 return returnDom ? n : Roo.get(n);
7290 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7291 * @param {String} selector The CSS selector
7292 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7293 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7295 down : function(selector, returnDom){
7296 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7297 return returnDom ? n : Roo.get(n);
7301 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7302 * @param {String} group The group the DD object is member of
7303 * @param {Object} config The DD config object
7304 * @param {Object} overrides An object containing methods to override/implement on the DD object
7305 * @return {Roo.dd.DD} The DD object
7307 initDD : function(group, config, overrides){
7308 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7309 return Roo.apply(dd, overrides);
7313 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7314 * @param {String} group The group the DDProxy object is member of
7315 * @param {Object} config The DDProxy config object
7316 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7317 * @return {Roo.dd.DDProxy} The DDProxy object
7319 initDDProxy : function(group, config, overrides){
7320 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7321 return Roo.apply(dd, overrides);
7325 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7326 * @param {String} group The group the DDTarget object is member of
7327 * @param {Object} config The DDTarget config object
7328 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7329 * @return {Roo.dd.DDTarget} The DDTarget object
7331 initDDTarget : function(group, config, overrides){
7332 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7333 return Roo.apply(dd, overrides);
7337 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7338 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7339 * @param {Boolean} visible Whether the element is visible
7340 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7341 * @return {Roo.Element} this
7343 setVisible : function(visible, animate){
7345 if(this.visibilityMode == El.DISPLAY){
7346 this.setDisplayed(visible);
7349 this.dom.style.visibility = visible ? "visible" : "hidden";
7352 // closure for composites
7354 var visMode = this.visibilityMode;
7356 this.setOpacity(.01);
7357 this.setVisible(true);
7359 this.anim({opacity: { to: (visible?1:0) }},
7360 this.preanim(arguments, 1),
7361 null, .35, 'easeIn', function(){
7363 if(visMode == El.DISPLAY){
7364 dom.style.display = "none";
7366 dom.style.visibility = "hidden";
7368 Roo.get(dom).setOpacity(1);
7376 * Returns true if display is not "none"
7379 isDisplayed : function() {
7380 return this.getStyle("display") != "none";
7384 * Toggles the element's visibility or display, depending on visibility mode.
7385 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7386 * @return {Roo.Element} this
7388 toggle : function(animate){
7389 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7394 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7395 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7396 * @return {Roo.Element} this
7398 setDisplayed : function(value) {
7399 if(typeof value == "boolean"){
7400 value = value ? this.originalDisplay : "none";
7402 this.setStyle("display", value);
7407 * Tries to focus the element. Any exceptions are caught and ignored.
7408 * @return {Roo.Element} this
7410 focus : function() {
7418 * Tries to blur the element. Any exceptions are caught and ignored.
7419 * @return {Roo.Element} this
7429 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7430 * @param {String/Array} className The CSS class to add, or an array of classes
7431 * @return {Roo.Element} this
7433 addClass : function(className){
7434 if(className instanceof Array){
7435 for(var i = 0, len = className.length; i < len; i++) {
7436 this.addClass(className[i]);
7439 if(className && !this.hasClass(className)){
7440 this.dom.className = this.dom.className + " " + className;
7447 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7448 * @param {String/Array} className The CSS class to add, or an array of classes
7449 * @return {Roo.Element} this
7451 radioClass : function(className){
7452 var siblings = this.dom.parentNode.childNodes;
7453 for(var i = 0; i < siblings.length; i++) {
7454 var s = siblings[i];
7455 if(s.nodeType == 1){
7456 Roo.get(s).removeClass(className);
7459 this.addClass(className);
7464 * Removes one or more CSS classes from the element.
7465 * @param {String/Array} className The CSS class to remove, or an array of classes
7466 * @return {Roo.Element} this
7468 removeClass : function(className){
7469 if(!className || !this.dom.className){
7472 if(className instanceof Array){
7473 for(var i = 0, len = className.length; i < len; i++) {
7474 this.removeClass(className[i]);
7477 if(this.hasClass(className)){
7478 var re = this.classReCache[className];
7480 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7481 this.classReCache[className] = re;
7483 this.dom.className =
7484 this.dom.className.replace(re, " ");
7494 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7495 * @param {String} className The CSS class to toggle
7496 * @return {Roo.Element} this
7498 toggleClass : function(className){
7499 if(this.hasClass(className)){
7500 this.removeClass(className);
7502 this.addClass(className);
7508 * Checks if the specified CSS class exists on this element's DOM node.
7509 * @param {String} className The CSS class to check for
7510 * @return {Boolean} True if the class exists, else false
7512 hasClass : function(className){
7513 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7517 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7518 * @param {String} oldClassName The CSS class to replace
7519 * @param {String} newClassName The replacement CSS class
7520 * @return {Roo.Element} this
7522 replaceClass : function(oldClassName, newClassName){
7523 this.removeClass(oldClassName);
7524 this.addClass(newClassName);
7529 * Returns an object with properties matching the styles requested.
7530 * For example, el.getStyles('color', 'font-size', 'width') might return
7531 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7532 * @param {String} style1 A style name
7533 * @param {String} style2 A style name
7534 * @param {String} etc.
7535 * @return {Object} The style object
7537 getStyles : function(){
7538 var a = arguments, len = a.length, r = {};
7539 for(var i = 0; i < len; i++){
7540 r[a[i]] = this.getStyle(a[i]);
7546 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7547 * @param {String} property The style property whose value is returned.
7548 * @return {String} The current value of the style property for this element.
7550 getStyle : function(){
7551 return view && view.getComputedStyle ?
7553 var el = this.dom, v, cs, camel;
7554 if(prop == 'float'){
7557 if(el.style && (v = el.style[prop])){
7560 if(cs = view.getComputedStyle(el, "")){
7561 if(!(camel = propCache[prop])){
7562 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7569 var el = this.dom, v, cs, camel;
7570 if(prop == 'opacity'){
7571 if(typeof el.style.filter == 'string'){
7572 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7574 var fv = parseFloat(m[1]);
7576 return fv ? fv / 100 : 0;
7581 }else if(prop == 'float'){
7582 prop = "styleFloat";
7584 if(!(camel = propCache[prop])){
7585 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7587 if(v = el.style[camel]){
7590 if(cs = el.currentStyle){
7598 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7599 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7600 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7601 * @return {Roo.Element} this
7603 setStyle : function(prop, value){
7604 if(typeof prop == "string"){
7606 if (prop == 'float') {
7607 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7612 if(!(camel = propCache[prop])){
7613 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7616 if(camel == 'opacity') {
7617 this.setOpacity(value);
7619 this.dom.style[camel] = value;
7622 for(var style in prop){
7623 if(typeof prop[style] != "function"){
7624 this.setStyle(style, prop[style]);
7632 * More flexible version of {@link #setStyle} for setting style properties.
7633 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7634 * a function which returns such a specification.
7635 * @return {Roo.Element} this
7637 applyStyles : function(style){
7638 Roo.DomHelper.applyStyles(this.dom, style);
7643 * 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).
7644 * @return {Number} The X position of the element
7647 return D.getX(this.dom);
7651 * 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).
7652 * @return {Number} The Y position of the element
7655 return D.getY(this.dom);
7659 * 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).
7660 * @return {Array} The XY position of the element
7663 return D.getXY(this.dom);
7667 * 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).
7668 * @param {Number} The X position of the element
7669 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7670 * @return {Roo.Element} this
7672 setX : function(x, animate){
7674 D.setX(this.dom, x);
7676 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7682 * 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).
7683 * @param {Number} The Y position of the element
7684 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7685 * @return {Roo.Element} this
7687 setY : function(y, animate){
7689 D.setY(this.dom, y);
7691 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7697 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7698 * @param {String} left The left CSS property value
7699 * @return {Roo.Element} this
7701 setLeft : function(left){
7702 this.setStyle("left", this.addUnits(left));
7707 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7708 * @param {String} top The top CSS property value
7709 * @return {Roo.Element} this
7711 setTop : function(top){
7712 this.setStyle("top", this.addUnits(top));
7717 * Sets the element's CSS right style.
7718 * @param {String} right The right CSS property value
7719 * @return {Roo.Element} this
7721 setRight : function(right){
7722 this.setStyle("right", this.addUnits(right));
7727 * Sets the element's CSS bottom style.
7728 * @param {String} bottom The bottom CSS property value
7729 * @return {Roo.Element} this
7731 setBottom : function(bottom){
7732 this.setStyle("bottom", this.addUnits(bottom));
7737 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7738 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7739 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7740 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7741 * @return {Roo.Element} this
7743 setXY : function(pos, animate){
7745 D.setXY(this.dom, pos);
7747 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7753 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7754 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7755 * @param {Number} x X value for new position (coordinates are page-based)
7756 * @param {Number} y Y value for new position (coordinates are page-based)
7757 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7758 * @return {Roo.Element} this
7760 setLocation : function(x, y, animate){
7761 this.setXY([x, y], this.preanim(arguments, 2));
7766 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7767 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7768 * @param {Number} x X value for new position (coordinates are page-based)
7769 * @param {Number} y Y value for new position (coordinates are page-based)
7770 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7771 * @return {Roo.Element} this
7773 moveTo : function(x, y, animate){
7774 this.setXY([x, y], this.preanim(arguments, 2));
7779 * Returns the region of the given element.
7780 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7781 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7783 getRegion : function(){
7784 return D.getRegion(this.dom);
7788 * Returns the offset height of the element
7789 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7790 * @return {Number} The element's height
7792 getHeight : function(contentHeight){
7793 var h = this.dom.offsetHeight || 0;
7794 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7798 * Returns the offset width of the element
7799 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7800 * @return {Number} The element's width
7802 getWidth : function(contentWidth){
7803 var w = this.dom.offsetWidth || 0;
7804 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7808 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7809 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7810 * if a height has not been set using CSS.
7813 getComputedHeight : function(){
7814 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7816 h = parseInt(this.getStyle('height'), 10) || 0;
7817 if(!this.isBorderBox()){
7818 h += this.getFrameWidth('tb');
7825 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7826 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7827 * if a width has not been set using CSS.
7830 getComputedWidth : function(){
7831 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7833 w = parseInt(this.getStyle('width'), 10) || 0;
7834 if(!this.isBorderBox()){
7835 w += this.getFrameWidth('lr');
7842 * Returns the size of the element.
7843 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7844 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7846 getSize : function(contentSize){
7847 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7851 * Returns the width and height of the viewport.
7852 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7854 getViewSize : function(){
7855 var d = this.dom, doc = document, aw = 0, ah = 0;
7856 if(d == doc || d == doc.body){
7857 return {width : D.getViewWidth(), height: D.getViewHeight()};
7860 width : d.clientWidth,
7861 height: d.clientHeight
7867 * Returns the value of the "value" attribute
7868 * @param {Boolean} asNumber true to parse the value as a number
7869 * @return {String/Number}
7871 getValue : function(asNumber){
7872 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7876 adjustWidth : function(width){
7877 if(typeof width == "number"){
7878 if(this.autoBoxAdjust && !this.isBorderBox()){
7879 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7889 adjustHeight : function(height){
7890 if(typeof height == "number"){
7891 if(this.autoBoxAdjust && !this.isBorderBox()){
7892 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7902 * Set the width of the element
7903 * @param {Number} width The new width
7904 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7905 * @return {Roo.Element} this
7907 setWidth : function(width, animate){
7908 width = this.adjustWidth(width);
7910 this.dom.style.width = this.addUnits(width);
7912 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7918 * Set the height of the element
7919 * @param {Number} height The new height
7920 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7921 * @return {Roo.Element} this
7923 setHeight : function(height, animate){
7924 height = this.adjustHeight(height);
7926 this.dom.style.height = this.addUnits(height);
7928 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7934 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7935 * @param {Number} width The new width
7936 * @param {Number} height The new height
7937 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7938 * @return {Roo.Element} this
7940 setSize : function(width, height, animate){
7941 if(typeof width == "object"){ // in case of object from getSize()
7942 height = width.height; width = width.width;
7944 width = this.adjustWidth(width); height = this.adjustHeight(height);
7946 this.dom.style.width = this.addUnits(width);
7947 this.dom.style.height = this.addUnits(height);
7949 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7955 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7956 * @param {Number} x X value for new position (coordinates are page-based)
7957 * @param {Number} y Y value for new position (coordinates are page-based)
7958 * @param {Number} width The new width
7959 * @param {Number} height The new height
7960 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961 * @return {Roo.Element} this
7963 setBounds : function(x, y, width, height, animate){
7965 this.setSize(width, height);
7966 this.setLocation(x, y);
7968 width = this.adjustWidth(width); height = this.adjustHeight(height);
7969 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7970 this.preanim(arguments, 4), 'motion');
7976 * 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.
7977 * @param {Roo.lib.Region} region The region to fill
7978 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7979 * @return {Roo.Element} this
7981 setRegion : function(region, animate){
7982 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7987 * Appends an event handler
7989 * @param {String} eventName The type of event to append
7990 * @param {Function} fn The method the event invokes
7991 * @param {Object} scope (optional) The scope (this object) of the fn
7992 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7994 addListener : function(eventName, fn, scope, options){
7996 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8001 * Removes an event handler from this element
8002 * @param {String} eventName the type of event to remove
8003 * @param {Function} fn the method the event invokes
8004 * @return {Roo.Element} this
8006 removeListener : function(eventName, fn){
8007 Roo.EventManager.removeListener(this.dom, eventName, fn);
8012 * Removes all previous added listeners from this element
8013 * @return {Roo.Element} this
8015 removeAllListeners : function(){
8016 E.purgeElement(this.dom);
8020 relayEvent : function(eventName, observable){
8021 this.on(eventName, function(e){
8022 observable.fireEvent(eventName, e);
8027 * Set the opacity of the element
8028 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8029 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8030 * @return {Roo.Element} this
8032 setOpacity : function(opacity, animate){
8034 var s = this.dom.style;
8037 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8038 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8040 s.opacity = opacity;
8043 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8049 * Gets the left X coordinate
8050 * @param {Boolean} local True to get the local css position instead of page coordinate
8053 getLeft : function(local){
8057 return parseInt(this.getStyle("left"), 10) || 0;
8062 * Gets the right X coordinate of the element (element X position + element width)
8063 * @param {Boolean} local True to get the local css position instead of page coordinate
8066 getRight : function(local){
8068 return this.getX() + this.getWidth();
8070 return (this.getLeft(true) + this.getWidth()) || 0;
8075 * Gets the top Y coordinate
8076 * @param {Boolean} local True to get the local css position instead of page coordinate
8079 getTop : function(local) {
8083 return parseInt(this.getStyle("top"), 10) || 0;
8088 * Gets the bottom Y coordinate of the element (element Y position + element height)
8089 * @param {Boolean} local True to get the local css position instead of page coordinate
8092 getBottom : function(local){
8094 return this.getY() + this.getHeight();
8096 return (this.getTop(true) + this.getHeight()) || 0;
8101 * Initializes positioning on this element. If a desired position is not passed, it will make the
8102 * the element positioned relative IF it is not already positioned.
8103 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8104 * @param {Number} zIndex (optional) The zIndex to apply
8105 * @param {Number} x (optional) Set the page X position
8106 * @param {Number} y (optional) Set the page Y position
8108 position : function(pos, zIndex, x, y){
8110 if(this.getStyle('position') == 'static'){
8111 this.setStyle('position', 'relative');
8114 this.setStyle("position", pos);
8117 this.setStyle("z-index", zIndex);
8119 if(x !== undefined && y !== undefined){
8121 }else if(x !== undefined){
8123 }else if(y !== undefined){
8129 * Clear positioning back to the default when the document was loaded
8130 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8131 * @return {Roo.Element} this
8133 clearPositioning : function(value){
8141 "position" : "static"
8147 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8148 * snapshot before performing an update and then restoring the element.
8151 getPositioning : function(){
8152 var l = this.getStyle("left");
8153 var t = this.getStyle("top");
8155 "position" : this.getStyle("position"),
8157 "right" : l ? "" : this.getStyle("right"),
8159 "bottom" : t ? "" : this.getStyle("bottom"),
8160 "z-index" : this.getStyle("z-index")
8165 * Gets the width of the border(s) for the specified side(s)
8166 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8167 * passing lr would get the border (l)eft width + the border (r)ight width.
8168 * @return {Number} The width of the sides passed added together
8170 getBorderWidth : function(side){
8171 return this.addStyles(side, El.borders);
8175 * Gets the width of the padding(s) for the specified side(s)
8176 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8177 * passing lr would get the padding (l)eft + the padding (r)ight.
8178 * @return {Number} The padding of the sides passed added together
8180 getPadding : function(side){
8181 return this.addStyles(side, El.paddings);
8185 * Set positioning with an object returned by getPositioning().
8186 * @param {Object} posCfg
8187 * @return {Roo.Element} this
8189 setPositioning : function(pc){
8190 this.applyStyles(pc);
8191 if(pc.right == "auto"){
8192 this.dom.style.right = "";
8194 if(pc.bottom == "auto"){
8195 this.dom.style.bottom = "";
8201 fixDisplay : function(){
8202 if(this.getStyle("display") == "none"){
8203 this.setStyle("visibility", "hidden");
8204 this.setStyle("display", this.originalDisplay); // first try reverting to default
8205 if(this.getStyle("display") == "none"){ // if that fails, default to block
8206 this.setStyle("display", "block");
8212 * Quick set left and top adding default units
8213 * @param {String} left The left CSS property value
8214 * @param {String} top The top CSS property value
8215 * @return {Roo.Element} this
8217 setLeftTop : function(left, top){
8218 this.dom.style.left = this.addUnits(left);
8219 this.dom.style.top = this.addUnits(top);
8224 * Move this element relative to its current position.
8225 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8226 * @param {Number} distance How far to move the element in pixels
8227 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8228 * @return {Roo.Element} this
8230 move : function(direction, distance, animate){
8231 var xy = this.getXY();
8232 direction = direction.toLowerCase();
8236 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8240 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8245 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8250 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8257 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8258 * @return {Roo.Element} this
8261 if(!this.isClipped){
8262 this.isClipped = true;
8263 this.originalClip = {
8264 "o": this.getStyle("overflow"),
8265 "x": this.getStyle("overflow-x"),
8266 "y": this.getStyle("overflow-y")
8268 this.setStyle("overflow", "hidden");
8269 this.setStyle("overflow-x", "hidden");
8270 this.setStyle("overflow-y", "hidden");
8276 * Return clipping (overflow) to original clipping before clip() was called
8277 * @return {Roo.Element} this
8279 unclip : function(){
8281 this.isClipped = false;
8282 var o = this.originalClip;
8283 if(o.o){this.setStyle("overflow", o.o);}
8284 if(o.x){this.setStyle("overflow-x", o.x);}
8285 if(o.y){this.setStyle("overflow-y", o.y);}
8292 * Gets the x,y coordinates specified by the anchor position on the element.
8293 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8294 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8295 * {width: (target width), height: (target height)} (defaults to the element's current size)
8296 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8297 * @return {Array} [x, y] An array containing the element's x and y coordinates
8299 getAnchorXY : function(anchor, local, s){
8300 //Passing a different size is useful for pre-calculating anchors,
8301 //especially for anchored animations that change the el size.
8303 var w, h, vp = false;
8306 if(d == document.body || d == document){
8308 w = D.getViewWidth(); h = D.getViewHeight();
8310 w = this.getWidth(); h = this.getHeight();
8313 w = s.width; h = s.height;
8315 var x = 0, y = 0, r = Math.round;
8316 switch((anchor || "tl").toLowerCase()){
8358 var sc = this.getScroll();
8359 return [x + sc.left, y + sc.top];
8361 //Add the element's offset xy
8362 var o = this.getXY();
8363 return [x+o[0], y+o[1]];
8367 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8368 * supported position values.
8369 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8370 * @param {String} position The position to align to.
8371 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8372 * @return {Array} [x, y]
8374 getAlignToXY : function(el, p, o){
8378 throw "Element.alignTo with an element that doesn't exist";
8380 var c = false; //constrain to viewport
8381 var p1 = "", p2 = "";
8388 }else if(p.indexOf("-") == -1){
8391 p = p.toLowerCase();
8392 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8394 throw "Element.alignTo with an invalid alignment " + p;
8396 p1 = m[1]; p2 = m[2]; c = !!m[3];
8398 //Subtract the aligned el's internal xy from the target's offset xy
8399 //plus custom offset to get the aligned el's new offset xy
8400 var a1 = this.getAnchorXY(p1, true);
8401 var a2 = el.getAnchorXY(p2, false);
8402 var x = a2[0] - a1[0] + o[0];
8403 var y = a2[1] - a1[1] + o[1];
8405 //constrain the aligned el to viewport if necessary
8406 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8407 // 5px of margin for ie
8408 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8410 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8411 //perpendicular to the vp border, allow the aligned el to slide on that border,
8412 //otherwise swap the aligned el to the opposite border of the target.
8413 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8414 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8415 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8416 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8419 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8420 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8422 if((x+w) > dw + scrollX){
8423 x = swapX ? r.left-w : dw+scrollX-w;
8426 x = swapX ? r.right : scrollX;
8428 if((y+h) > dh + scrollY){
8429 y = swapY ? r.top-h : dh+scrollY-h;
8432 y = swapY ? r.bottom : scrollY;
8439 getConstrainToXY : function(){
8440 var os = {top:0, left:0, bottom:0, right: 0};
8442 return function(el, local, offsets, proposedXY){
8444 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8446 var vw, vh, vx = 0, vy = 0;
8447 if(el.dom == document.body || el.dom == document){
8448 vw = Roo.lib.Dom.getViewWidth();
8449 vh = Roo.lib.Dom.getViewHeight();
8451 vw = el.dom.clientWidth;
8452 vh = el.dom.clientHeight;
8454 var vxy = el.getXY();
8460 var s = el.getScroll();
8462 vx += offsets.left + s.left;
8463 vy += offsets.top + s.top;
8465 vw -= offsets.right;
8466 vh -= offsets.bottom;
8471 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8472 var x = xy[0], y = xy[1];
8473 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8475 // only move it if it needs it
8478 // first validate right/bottom
8487 // then make sure top/left isn't negative
8496 return moved ? [x, y] : false;
8501 adjustForConstraints : function(xy, parent, offsets){
8502 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8506 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8507 * document it aligns it to the viewport.
8508 * The position parameter is optional, and can be specified in any one of the following formats:
8510 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8511 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8512 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8513 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8514 * <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
8515 * element's anchor point, and the second value is used as the target's anchor point.</li>
8517 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8518 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8519 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8520 * that specified in order to enforce the viewport constraints.
8521 * Following are all of the supported anchor positions:
8524 ----- -----------------------------
8525 tl The top left corner (default)
8526 t The center of the top edge
8527 tr The top right corner
8528 l The center of the left edge
8529 c In the center of the element
8530 r The center of the right edge
8531 bl The bottom left corner
8532 b The center of the bottom edge
8533 br The bottom right corner
8537 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8538 el.alignTo("other-el");
8540 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8541 el.alignTo("other-el", "tr?");
8543 // align the bottom right corner of el with the center left edge of other-el
8544 el.alignTo("other-el", "br-l?");
8546 // align the center of el with the bottom left corner of other-el and
8547 // adjust the x position by -6 pixels (and the y position by 0)
8548 el.alignTo("other-el", "c-bl", [-6, 0]);
8550 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8551 * @param {String} position The position to align to.
8552 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8553 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8554 * @return {Roo.Element} this
8556 alignTo : function(element, position, offsets, animate){
8557 var xy = this.getAlignToXY(element, position, offsets);
8558 this.setXY(xy, this.preanim(arguments, 3));
8563 * Anchors an element to another element and realigns it when the window is resized.
8564 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8565 * @param {String} position The position to align to.
8566 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8567 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8568 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8569 * is a number, it is used as the buffer delay (defaults to 50ms).
8570 * @param {Function} callback The function to call after the animation finishes
8571 * @return {Roo.Element} this
8573 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8574 var action = function(){
8575 this.alignTo(el, alignment, offsets, animate);
8576 Roo.callback(callback, this);
8578 Roo.EventManager.onWindowResize(action, this);
8579 var tm = typeof monitorScroll;
8580 if(tm != 'undefined'){
8581 Roo.EventManager.on(window, 'scroll', action, this,
8582 {buffer: tm == 'number' ? monitorScroll : 50});
8584 action.call(this); // align immediately
8588 * Clears any opacity settings from this element. Required in some cases for IE.
8589 * @return {Roo.Element} this
8591 clearOpacity : function(){
8592 if (window.ActiveXObject) {
8593 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8594 this.dom.style.filter = "";
8597 this.dom.style.opacity = "";
8598 this.dom.style["-moz-opacity"] = "";
8599 this.dom.style["-khtml-opacity"] = "";
8605 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8606 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8607 * @return {Roo.Element} this
8609 hide : function(animate){
8610 this.setVisible(false, this.preanim(arguments, 0));
8615 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8616 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8617 * @return {Roo.Element} this
8619 show : function(animate){
8620 this.setVisible(true, this.preanim(arguments, 0));
8625 * @private Test if size has a unit, otherwise appends the default
8627 addUnits : function(size){
8628 return Roo.Element.addUnits(size, this.defaultUnit);
8632 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8633 * @return {Roo.Element} this
8635 beginMeasure : function(){
8637 if(el.offsetWidth || el.offsetHeight){
8638 return this; // offsets work already
8641 var p = this.dom, b = document.body; // start with this element
8642 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8643 var pe = Roo.get(p);
8644 if(pe.getStyle('display') == 'none'){
8645 changed.push({el: p, visibility: pe.getStyle("visibility")});
8646 p.style.visibility = "hidden";
8647 p.style.display = "block";
8651 this._measureChanged = changed;
8657 * Restores displays to before beginMeasure was called
8658 * @return {Roo.Element} this
8660 endMeasure : function(){
8661 var changed = this._measureChanged;
8663 for(var i = 0, len = changed.length; i < len; i++) {
8665 r.el.style.visibility = r.visibility;
8666 r.el.style.display = "none";
8668 this._measureChanged = null;
8674 * Update the innerHTML of this element, optionally searching for and processing scripts
8675 * @param {String} html The new HTML
8676 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8677 * @param {Function} callback For async script loading you can be noticed when the update completes
8678 * @return {Roo.Element} this
8680 update : function(html, loadScripts, callback){
8681 if(typeof html == "undefined"){
8684 if(loadScripts !== true){
8685 this.dom.innerHTML = html;
8686 if(typeof callback == "function"){
8694 html += '<span id="' + id + '"></span>';
8696 E.onAvailable(id, function(){
8697 var hd = document.getElementsByTagName("head")[0];
8698 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8699 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8700 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8703 while(match = re.exec(html)){
8704 var attrs = match[1];
8705 var srcMatch = attrs ? attrs.match(srcRe) : false;
8706 if(srcMatch && srcMatch[2]){
8707 var s = document.createElement("script");
8708 s.src = srcMatch[2];
8709 var typeMatch = attrs.match(typeRe);
8710 if(typeMatch && typeMatch[2]){
8711 s.type = typeMatch[2];
8714 }else if(match[2] && match[2].length > 0){
8715 if(window.execScript) {
8716 window.execScript(match[2]);
8724 window.eval(match[2]);
8728 var el = document.getElementById(id);
8729 if(el){el.parentNode.removeChild(el);}
8730 if(typeof callback == "function"){
8734 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8739 * Direct access to the UpdateManager update() method (takes the same parameters).
8740 * @param {String/Function} url The url for this request or a function to call to get the url
8741 * @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}
8742 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8743 * @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.
8744 * @return {Roo.Element} this
8747 var um = this.getUpdateManager();
8748 um.update.apply(um, arguments);
8753 * Gets this element's UpdateManager
8754 * @return {Roo.UpdateManager} The UpdateManager
8756 getUpdateManager : function(){
8757 if(!this.updateManager){
8758 this.updateManager = new Roo.UpdateManager(this);
8760 return this.updateManager;
8764 * Disables text selection for this element (normalized across browsers)
8765 * @return {Roo.Element} this
8767 unselectable : function(){
8768 this.dom.unselectable = "on";
8769 this.swallowEvent("selectstart", true);
8770 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8771 this.addClass("x-unselectable");
8776 * Calculates the x, y to center this element on the screen
8777 * @return {Array} The x, y values [x, y]
8779 getCenterXY : function(){
8780 return this.getAlignToXY(document, 'c-c');
8784 * Centers the Element in either the viewport, or another Element.
8785 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8787 center : function(centerIn){
8788 this.alignTo(centerIn || document, 'c-c');
8793 * Tests various css rules/browsers to determine if this element uses a border box
8796 isBorderBox : function(){
8797 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8801 * Return a box {x, y, width, height} that can be used to set another elements
8802 * size/location to match this element.
8803 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8804 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8805 * @return {Object} box An object in the format {x, y, width, height}
8807 getBox : function(contentBox, local){
8812 var left = parseInt(this.getStyle("left"), 10) || 0;
8813 var top = parseInt(this.getStyle("top"), 10) || 0;
8816 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8818 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8820 var l = this.getBorderWidth("l")+this.getPadding("l");
8821 var r = this.getBorderWidth("r")+this.getPadding("r");
8822 var t = this.getBorderWidth("t")+this.getPadding("t");
8823 var b = this.getBorderWidth("b")+this.getPadding("b");
8824 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)};
8826 bx.right = bx.x + bx.width;
8827 bx.bottom = bx.y + bx.height;
8832 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8833 for more information about the sides.
8834 * @param {String} sides
8837 getFrameWidth : function(sides, onlyContentBox){
8838 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8842 * 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.
8843 * @param {Object} box The box to fill {x, y, width, height}
8844 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8845 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8846 * @return {Roo.Element} this
8848 setBox : function(box, adjust, animate){
8849 var w = box.width, h = box.height;
8850 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8851 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8852 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8854 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8859 * Forces the browser to repaint this element
8860 * @return {Roo.Element} this
8862 repaint : function(){
8864 this.addClass("x-repaint");
8865 setTimeout(function(){
8866 Roo.get(dom).removeClass("x-repaint");
8872 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8873 * then it returns the calculated width of the sides (see getPadding)
8874 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8875 * @return {Object/Number}
8877 getMargins : function(side){
8880 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8881 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8882 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8883 right: parseInt(this.getStyle("margin-right"), 10) || 0
8886 return this.addStyles(side, El.margins);
8891 addStyles : function(sides, styles){
8893 for(var i = 0, len = sides.length; i < len; i++){
8894 v = this.getStyle(styles[sides.charAt(i)]);
8896 w = parseInt(v, 10);
8904 * Creates a proxy element of this element
8905 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8906 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8907 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8908 * @return {Roo.Element} The new proxy element
8910 createProxy : function(config, renderTo, matchBox){
8912 renderTo = Roo.getDom(renderTo);
8914 renderTo = document.body;
8916 config = typeof config == "object" ?
8917 config : {tag : "div", cls: config};
8918 var proxy = Roo.DomHelper.append(renderTo, config, true);
8920 proxy.setBox(this.getBox());
8926 * Puts a mask over this element to disable user interaction. Requires core.css.
8927 * This method can only be applied to elements which accept child nodes.
8928 * @param {String} msg (optional) A message to display in the mask
8929 * @param {String} msgCls (optional) A css class to apply to the msg element
8930 * @return {Element} The mask element
8932 mask : function(msg, msgCls)
8934 if(this.getStyle("position") == "static"){
8935 this.setStyle("position", "relative");
8938 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8940 this.addClass("x-masked");
8941 this._mask.setDisplayed(true);
8946 while (dom && dom.style) {
8947 if (!isNaN(parseInt(dom.style.zIndex))) {
8948 z = Math.max(z, parseInt(dom.style.zIndex));
8950 dom = dom.parentNode;
8952 // if we are masking the body - then it hides everything..
8953 if (this.dom == document.body) {
8955 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8956 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8959 if(typeof msg == 'string'){
8961 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8963 var mm = this._maskMsg;
8964 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8965 mm.dom.firstChild.innerHTML = msg;
8966 mm.setDisplayed(true);
8968 mm.setStyle('z-index', z + 102);
8970 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8971 this._mask.setHeight(this.getHeight());
8973 this._mask.setStyle('z-index', z + 100);
8979 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8980 * it is cached for reuse.
8982 unmask : function(removeEl){
8984 if(removeEl === true){
8985 this._mask.remove();
8988 this._maskMsg.remove();
8989 delete this._maskMsg;
8992 this._mask.setDisplayed(false);
8994 this._maskMsg.setDisplayed(false);
8998 this.removeClass("x-masked");
9002 * Returns true if this element is masked
9005 isMasked : function(){
9006 return this._mask && this._mask.isVisible();
9010 * Creates an iframe shim for this element to keep selects and other windowed objects from
9012 * @return {Roo.Element} The new shim element
9014 createShim : function(){
9015 var el = document.createElement('iframe');
9016 el.frameBorder = 'no';
9017 el.className = 'roo-shim';
9018 if(Roo.isIE && Roo.isSecure){
9019 el.src = Roo.SSL_SECURE_URL;
9021 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9022 shim.autoBoxAdjust = false;
9027 * Removes this element from the DOM and deletes it from the cache
9029 remove : function(){
9030 if(this.dom.parentNode){
9031 this.dom.parentNode.removeChild(this.dom);
9033 delete El.cache[this.dom.id];
9037 * Sets up event handlers to add and remove a css class when the mouse is over this element
9038 * @param {String} className
9039 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9040 * mouseout events for children elements
9041 * @return {Roo.Element} this
9043 addClassOnOver : function(className, preventFlicker){
9044 this.on("mouseover", function(){
9045 Roo.fly(this, '_internal').addClass(className);
9047 var removeFn = function(e){
9048 if(preventFlicker !== true || !e.within(this, true)){
9049 Roo.fly(this, '_internal').removeClass(className);
9052 this.on("mouseout", removeFn, this.dom);
9057 * Sets up event handlers to add and remove a css class when this element has the focus
9058 * @param {String} className
9059 * @return {Roo.Element} this
9061 addClassOnFocus : function(className){
9062 this.on("focus", function(){
9063 Roo.fly(this, '_internal').addClass(className);
9065 this.on("blur", function(){
9066 Roo.fly(this, '_internal').removeClass(className);
9071 * 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)
9072 * @param {String} className
9073 * @return {Roo.Element} this
9075 addClassOnClick : function(className){
9077 this.on("mousedown", function(){
9078 Roo.fly(dom, '_internal').addClass(className);
9079 var d = Roo.get(document);
9080 var fn = function(){
9081 Roo.fly(dom, '_internal').removeClass(className);
9082 d.removeListener("mouseup", fn);
9084 d.on("mouseup", fn);
9090 * Stops the specified event from bubbling and optionally prevents the default action
9091 * @param {String} eventName
9092 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9093 * @return {Roo.Element} this
9095 swallowEvent : function(eventName, preventDefault){
9096 var fn = function(e){
9097 e.stopPropagation();
9102 if(eventName instanceof Array){
9103 for(var i = 0, len = eventName.length; i < len; i++){
9104 this.on(eventName[i], fn);
9108 this.on(eventName, fn);
9115 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9118 * Sizes this element to its parent element's dimensions performing
9119 * neccessary box adjustments.
9120 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9121 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9122 * @return {Roo.Element} this
9124 fitToParent : function(monitorResize, targetParent) {
9125 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9126 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9127 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9130 var p = Roo.get(targetParent || this.dom.parentNode);
9131 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9132 if (monitorResize === true) {
9133 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9134 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9140 * Gets the next sibling, skipping text nodes
9141 * @return {HTMLElement} The next sibling or null
9143 getNextSibling : function(){
9144 var n = this.dom.nextSibling;
9145 while(n && n.nodeType != 1){
9152 * Gets the previous sibling, skipping text nodes
9153 * @return {HTMLElement} The previous sibling or null
9155 getPrevSibling : function(){
9156 var n = this.dom.previousSibling;
9157 while(n && n.nodeType != 1){
9158 n = n.previousSibling;
9165 * Appends the passed element(s) to this element
9166 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9167 * @return {Roo.Element} this
9169 appendChild: function(el){
9176 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9177 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9178 * automatically generated with the specified attributes.
9179 * @param {HTMLElement} insertBefore (optional) a child element of this element
9180 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9181 * @return {Roo.Element} The new child element
9183 createChild: function(config, insertBefore, returnDom){
9184 config = config || {tag:'div'};
9186 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9188 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9192 * Appends this element to the passed element
9193 * @param {String/HTMLElement/Element} el The new parent element
9194 * @return {Roo.Element} this
9196 appendTo: function(el){
9197 el = Roo.getDom(el);
9198 el.appendChild(this.dom);
9203 * Inserts this element before the passed element in the DOM
9204 * @param {String/HTMLElement/Element} el The element to insert before
9205 * @return {Roo.Element} this
9207 insertBefore: function(el){
9208 el = Roo.getDom(el);
9209 el.parentNode.insertBefore(this.dom, el);
9214 * Inserts this element after the passed element in the DOM
9215 * @param {String/HTMLElement/Element} el The element to insert after
9216 * @return {Roo.Element} this
9218 insertAfter: function(el){
9219 el = Roo.getDom(el);
9220 el.parentNode.insertBefore(this.dom, el.nextSibling);
9225 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9226 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9227 * @return {Roo.Element} The new child
9229 insertFirst: function(el, returnDom){
9231 if(typeof el == 'object' && !el.nodeType){ // dh config
9232 return this.createChild(el, this.dom.firstChild, returnDom);
9234 el = Roo.getDom(el);
9235 this.dom.insertBefore(el, this.dom.firstChild);
9236 return !returnDom ? Roo.get(el) : el;
9241 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9242 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9243 * @param {String} where (optional) 'before' or 'after' defaults to before
9244 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9245 * @return {Roo.Element} the inserted Element
9247 insertSibling: function(el, where, returnDom){
9248 where = where ? where.toLowerCase() : 'before';
9250 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9252 if(typeof el == 'object' && !el.nodeType){ // dh config
9253 if(where == 'after' && !this.dom.nextSibling){
9254 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9256 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9260 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9261 where == 'before' ? this.dom : this.dom.nextSibling);
9270 * Creates and wraps this element with another element
9271 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9272 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9273 * @return {HTMLElement/Element} The newly created wrapper element
9275 wrap: function(config, returnDom){
9277 config = {tag: "div"};
9279 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9280 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9285 * Replaces the passed element with this element
9286 * @param {String/HTMLElement/Element} el The element to replace
9287 * @return {Roo.Element} this
9289 replace: function(el){
9291 this.insertBefore(el);
9297 * Inserts an html fragment into this element
9298 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9299 * @param {String} html The HTML fragment
9300 * @param {Boolean} returnEl True to return an Roo.Element
9301 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9303 insertHtml : function(where, html, returnEl){
9304 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9305 return returnEl ? Roo.get(el) : el;
9309 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9310 * @param {Object} o The object with the attributes
9311 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9312 * @return {Roo.Element} this
9314 set : function(o, useSet){
9316 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9318 if(attr == "style" || typeof o[attr] == "function") continue;
9320 el.className = o["cls"];
9322 if(useSet) el.setAttribute(attr, o[attr]);
9323 else el[attr] = o[attr];
9327 Roo.DomHelper.applyStyles(el, o.style);
9333 * Convenience method for constructing a KeyMap
9334 * @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:
9335 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9336 * @param {Function} fn The function to call
9337 * @param {Object} scope (optional) The scope of the function
9338 * @return {Roo.KeyMap} The KeyMap created
9340 addKeyListener : function(key, fn, scope){
9342 if(typeof key != "object" || key instanceof Array){
9358 return new Roo.KeyMap(this, config);
9362 * Creates a KeyMap for this element
9363 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9364 * @return {Roo.KeyMap} The KeyMap created
9366 addKeyMap : function(config){
9367 return new Roo.KeyMap(this, config);
9371 * Returns true if this element is scrollable.
9374 isScrollable : function(){
9376 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9380 * 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().
9381 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9382 * @param {Number} value The new scroll value
9383 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9384 * @return {Element} this
9387 scrollTo : function(side, value, animate){
9388 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9390 this.dom[prop] = value;
9392 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9393 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9399 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9400 * within this element's scrollable range.
9401 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9402 * @param {Number} distance How far to scroll the element in pixels
9403 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9404 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9405 * was scrolled as far as it could go.
9407 scroll : function(direction, distance, animate){
9408 if(!this.isScrollable()){
9412 var l = el.scrollLeft, t = el.scrollTop;
9413 var w = el.scrollWidth, h = el.scrollHeight;
9414 var cw = el.clientWidth, ch = el.clientHeight;
9415 direction = direction.toLowerCase();
9416 var scrolled = false;
9417 var a = this.preanim(arguments, 2);
9422 var v = Math.min(l + distance, w-cw);
9423 this.scrollTo("left", v, a);
9430 var v = Math.max(l - distance, 0);
9431 this.scrollTo("left", v, a);
9439 var v = Math.max(t - distance, 0);
9440 this.scrollTo("top", v, a);
9448 var v = Math.min(t + distance, h-ch);
9449 this.scrollTo("top", v, a);
9458 * Translates the passed page coordinates into left/top css values for this element
9459 * @param {Number/Array} x The page x or an array containing [x, y]
9460 * @param {Number} y The page y
9461 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9463 translatePoints : function(x, y){
9464 if(typeof x == 'object' || x instanceof Array){
9467 var p = this.getStyle('position');
9468 var o = this.getXY();
9470 var l = parseInt(this.getStyle('left'), 10);
9471 var t = parseInt(this.getStyle('top'), 10);
9474 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9477 t = (p == "relative") ? 0 : this.dom.offsetTop;
9480 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9484 * Returns the current scroll position of the element.
9485 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9487 getScroll : function(){
9488 var d = this.dom, doc = document;
9489 if(d == doc || d == doc.body){
9490 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9491 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9492 return {left: l, top: t};
9494 return {left: d.scrollLeft, top: d.scrollTop};
9499 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9500 * are convert to standard 6 digit hex color.
9501 * @param {String} attr The css attribute
9502 * @param {String} defaultValue The default value to use when a valid color isn't found
9503 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9506 getColor : function(attr, defaultValue, prefix){
9507 var v = this.getStyle(attr);
9508 if(!v || v == "transparent" || v == "inherit") {
9509 return defaultValue;
9511 var color = typeof prefix == "undefined" ? "#" : prefix;
9512 if(v.substr(0, 4) == "rgb("){
9513 var rvs = v.slice(4, v.length -1).split(",");
9514 for(var i = 0; i < 3; i++){
9515 var h = parseInt(rvs[i]).toString(16);
9522 if(v.substr(0, 1) == "#"){
9524 for(var i = 1; i < 4; i++){
9525 var c = v.charAt(i);
9528 }else if(v.length == 7){
9529 color += v.substr(1);
9533 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9537 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9538 * gradient background, rounded corners and a 4-way shadow.
9539 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9540 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9541 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9542 * @return {Roo.Element} this
9544 boxWrap : function(cls){
9545 cls = cls || 'x-box';
9546 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9547 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9552 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9553 * @param {String} namespace The namespace in which to look for the attribute
9554 * @param {String} name The attribute name
9555 * @return {String} The attribute value
9557 getAttributeNS : Roo.isIE ? function(ns, name){
9559 var type = typeof d[ns+":"+name];
9560 if(type != 'undefined' && type != 'unknown'){
9561 return d[ns+":"+name];
9564 } : function(ns, name){
9566 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9571 * Sets or Returns the value the dom attribute value
9572 * @param {String} name The attribute name
9573 * @param {String} value (optional) The value to set the attribute to
9574 * @return {String} The attribute value
9576 attr : function(name){
9577 if (arguments.length > 1) {
9578 this.dom.setAttribute(name, arguments[1]);
9579 return arguments[1];
9581 if (!this.dom.hasAttribute(name)) {
9584 return this.dom.getAttribute(name);
9591 var ep = El.prototype;
9594 * Appends an event handler (Shorthand for addListener)
9595 * @param {String} eventName The type of event to append
9596 * @param {Function} fn The method the event invokes
9597 * @param {Object} scope (optional) The scope (this object) of the fn
9598 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9601 ep.on = ep.addListener;
9603 ep.mon = ep.addListener;
9606 * Removes an event handler from this element (shorthand for removeListener)
9607 * @param {String} eventName the type of event to remove
9608 * @param {Function} fn the method the event invokes
9609 * @return {Roo.Element} this
9612 ep.un = ep.removeListener;
9615 * true to automatically adjust width and height settings for box-model issues (default to true)
9617 ep.autoBoxAdjust = true;
9620 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9623 El.addUnits = function(v, defaultUnit){
9624 if(v === "" || v == "auto"){
9627 if(v === undefined){
9630 if(typeof v == "number" || !El.unitPattern.test(v)){
9631 return v + (defaultUnit || 'px');
9636 // special markup used throughout Roo when box wrapping elements
9637 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>';
9639 * Visibility mode constant - Use visibility to hide element
9645 * Visibility mode constant - Use display to hide element
9651 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9652 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9653 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9665 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9666 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9667 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9668 * @return {Element} The Element object
9671 El.get = function(el){
9673 if(!el){ return null; }
9674 if(typeof el == "string"){ // element id
9675 if(!(elm = document.getElementById(el))){
9678 if(ex = El.cache[el]){
9681 ex = El.cache[el] = new El(elm);
9684 }else if(el.tagName){ // dom element
9688 if(ex = El.cache[id]){
9691 ex = El.cache[id] = new El(el);
9694 }else if(el instanceof El){
9696 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9697 // catch case where it hasn't been appended
9698 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9701 }else if(el.isComposite){
9703 }else if(el instanceof Array){
9704 return El.select(el);
9705 }else if(el == document){
9706 // create a bogus element object representing the document object
9708 var f = function(){};
9709 f.prototype = El.prototype;
9711 docEl.dom = document;
9719 El.uncache = function(el){
9720 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9722 delete El.cache[a[i].id || a[i]];
9728 // Garbage collection - uncache elements/purge listeners on orphaned elements
9729 // so we don't hold a reference and cause the browser to retain them
9730 El.garbageCollect = function(){
9731 if(!Roo.enableGarbageCollector){
9732 clearInterval(El.collectorThread);
9735 for(var eid in El.cache){
9736 var el = El.cache[eid], d = el.dom;
9737 // -------------------------------------------------------
9738 // Determining what is garbage:
9739 // -------------------------------------------------------
9741 // dom node is null, definitely garbage
9742 // -------------------------------------------------------
9744 // no parentNode == direct orphan, definitely garbage
9745 // -------------------------------------------------------
9746 // !d.offsetParent && !document.getElementById(eid)
9747 // display none elements have no offsetParent so we will
9748 // also try to look it up by it's id. However, check
9749 // offsetParent first so we don't do unneeded lookups.
9750 // This enables collection of elements that are not orphans
9751 // directly, but somewhere up the line they have an orphan
9753 // -------------------------------------------------------
9754 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9755 delete El.cache[eid];
9756 if(d && Roo.enableListenerCollection){
9762 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9766 El.Flyweight = function(dom){
9769 El.Flyweight.prototype = El.prototype;
9771 El._flyweights = {};
9773 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9774 * the dom node can be overwritten by other code.
9775 * @param {String/HTMLElement} el The dom node or id
9776 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9777 * prevent conflicts (e.g. internally Roo uses "_internal")
9779 * @return {Element} The shared Element object
9781 El.fly = function(el, named){
9782 named = named || '_global';
9783 el = Roo.getDom(el);
9787 if(!El._flyweights[named]){
9788 El._flyweights[named] = new El.Flyweight();
9790 El._flyweights[named].dom = el;
9791 return El._flyweights[named];
9795 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9796 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9797 * Shorthand of {@link Roo.Element#get}
9798 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9799 * @return {Element} The Element object
9805 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9806 * the dom node can be overwritten by other code.
9807 * Shorthand of {@link Roo.Element#fly}
9808 * @param {String/HTMLElement} el The dom node or id
9809 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9810 * prevent conflicts (e.g. internally Roo uses "_internal")
9812 * @return {Element} The shared Element object
9818 // speedy lookup for elements never to box adjust
9819 var noBoxAdjust = Roo.isStrict ? {
9822 input:1, select:1, textarea:1
9824 if(Roo.isIE || Roo.isGecko){
9825 noBoxAdjust['button'] = 1;
9829 Roo.EventManager.on(window, 'unload', function(){
9831 delete El._flyweights;
9839 Roo.Element.selectorFunction = Roo.DomQuery.select;
9842 Roo.Element.select = function(selector, unique, root){
9844 if(typeof selector == "string"){
9845 els = Roo.Element.selectorFunction(selector, root);
9846 }else if(selector.length !== undefined){
9849 throw "Invalid selector";
9851 if(unique === true){
9852 return new Roo.CompositeElement(els);
9854 return new Roo.CompositeElementLite(els);
9858 * Selects elements based on the passed CSS selector to enable working on them as 1.
9859 * @param {String/Array} selector The CSS selector or an array of elements
9860 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9861 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9862 * @return {CompositeElementLite/CompositeElement}
9866 Roo.select = Roo.Element.select;
9883 * Ext JS Library 1.1.1
9884 * Copyright(c) 2006-2007, Ext JS, LLC.
9886 * Originally Released Under LGPL - original licence link has changed is not relivant.
9889 * <script type="text/javascript">
9894 //Notifies Element that fx methods are available
9895 Roo.enableFx = true;
9899 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9900 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9901 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9902 * Element effects to work.</p><br/>
9904 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9905 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9906 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9907 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9908 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9909 * expected results and should be done with care.</p><br/>
9911 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9912 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9915 ----- -----------------------------
9916 tl The top left corner
9917 t The center of the top edge
9918 tr The top right corner
9919 l The center of the left edge
9920 r The center of the right edge
9921 bl The bottom left corner
9922 b The center of the bottom edge
9923 br The bottom right corner
9925 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9926 * below are common options that can be passed to any Fx method.</b>
9927 * @cfg {Function} callback A function called when the effect is finished
9928 * @cfg {Object} scope The scope of the effect function
9929 * @cfg {String} easing A valid Easing value for the effect
9930 * @cfg {String} afterCls A css class to apply after the effect
9931 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9932 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9933 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9934 * effects that end with the element being visually hidden, ignored otherwise)
9935 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9936 * a function which returns such a specification that will be applied to the Element after the effect finishes
9937 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9938 * @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
9939 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9943 * Slides the element into view. An anchor point can be optionally passed to set the point of
9944 * origin for the slide effect. This function automatically handles wrapping the element with
9945 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9948 // default: slide the element in from the top
9951 // custom: slide the element in from the right with a 2-second duration
9952 el.slideIn('r', { duration: 2 });
9954 // common config options shown with default values
9960 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9961 * @param {Object} options (optional) Object literal with any of the Fx config options
9962 * @return {Roo.Element} The Element
9964 slideIn : function(anchor, o){
9965 var el = this.getFxEl();
9968 el.queueFx(o, function(){
9970 anchor = anchor || "t";
9972 // fix display to visibility
9975 // restore values after effect
9976 var r = this.getFxRestore();
9977 var b = this.getBox();
9978 // fixed size for slide
9982 var wrap = this.fxWrap(r.pos, o, "hidden");
9984 var st = this.dom.style;
9985 st.visibility = "visible";
9986 st.position = "absolute";
9988 // clear out temp styles after slide and unwrap
9989 var after = function(){
9990 el.fxUnwrap(wrap, r.pos, o);
9992 st.height = r.height;
9995 // time to calc the positions
9996 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9998 switch(anchor.toLowerCase()){
10000 wrap.setSize(b.width, 0);
10001 st.left = st.bottom = "0";
10005 wrap.setSize(0, b.height);
10006 st.right = st.top = "0";
10010 wrap.setSize(0, b.height);
10011 wrap.setX(b.right);
10012 st.left = st.top = "0";
10013 a = {width: bw, points: pt};
10016 wrap.setSize(b.width, 0);
10017 wrap.setY(b.bottom);
10018 st.left = st.top = "0";
10019 a = {height: bh, points: pt};
10022 wrap.setSize(0, 0);
10023 st.right = st.bottom = "0";
10024 a = {width: bw, height: bh};
10027 wrap.setSize(0, 0);
10028 wrap.setY(b.y+b.height);
10029 st.right = st.top = "0";
10030 a = {width: bw, height: bh, points: pt};
10033 wrap.setSize(0, 0);
10034 wrap.setXY([b.right, b.bottom]);
10035 st.left = st.top = "0";
10036 a = {width: bw, height: bh, points: pt};
10039 wrap.setSize(0, 0);
10040 wrap.setX(b.x+b.width);
10041 st.left = st.bottom = "0";
10042 a = {width: bw, height: bh, points: pt};
10045 this.dom.style.visibility = "visible";
10048 arguments.callee.anim = wrap.fxanim(a,
10058 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10059 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10060 * 'hidden') but block elements will still take up space in the document. The element must be removed
10061 * from the DOM using the 'remove' config option if desired. This function automatically handles
10062 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10065 // default: slide the element out to the top
10068 // custom: slide the element out to the right with a 2-second duration
10069 el.slideOut('r', { duration: 2 });
10071 // common config options shown with default values
10079 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10080 * @param {Object} options (optional) Object literal with any of the Fx config options
10081 * @return {Roo.Element} The Element
10083 slideOut : function(anchor, o){
10084 var el = this.getFxEl();
10087 el.queueFx(o, function(){
10089 anchor = anchor || "t";
10091 // restore values after effect
10092 var r = this.getFxRestore();
10094 var b = this.getBox();
10095 // fixed size for slide
10099 var wrap = this.fxWrap(r.pos, o, "visible");
10101 var st = this.dom.style;
10102 st.visibility = "visible";
10103 st.position = "absolute";
10107 var after = function(){
10109 el.setDisplayed(false);
10114 el.fxUnwrap(wrap, r.pos, o);
10116 st.width = r.width;
10117 st.height = r.height;
10122 var a, zero = {to: 0};
10123 switch(anchor.toLowerCase()){
10125 st.left = st.bottom = "0";
10126 a = {height: zero};
10129 st.right = st.top = "0";
10133 st.left = st.top = "0";
10134 a = {width: zero, points: {to:[b.right, b.y]}};
10137 st.left = st.top = "0";
10138 a = {height: zero, points: {to:[b.x, b.bottom]}};
10141 st.right = st.bottom = "0";
10142 a = {width: zero, height: zero};
10145 st.right = st.top = "0";
10146 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10149 st.left = st.top = "0";
10150 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10153 st.left = st.bottom = "0";
10154 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10158 arguments.callee.anim = wrap.fxanim(a,
10168 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10169 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10170 * The element must be removed from the DOM using the 'remove' config option if desired.
10176 // common config options shown with default values
10184 * @param {Object} options (optional) Object literal with any of the Fx config options
10185 * @return {Roo.Element} The Element
10187 puff : function(o){
10188 var el = this.getFxEl();
10191 el.queueFx(o, function(){
10192 this.clearOpacity();
10195 // restore values after effect
10196 var r = this.getFxRestore();
10197 var st = this.dom.style;
10199 var after = function(){
10201 el.setDisplayed(false);
10208 el.setPositioning(r.pos);
10209 st.width = r.width;
10210 st.height = r.height;
10215 var width = this.getWidth();
10216 var height = this.getHeight();
10218 arguments.callee.anim = this.fxanim({
10219 width : {to: this.adjustWidth(width * 2)},
10220 height : {to: this.adjustHeight(height * 2)},
10221 points : {by: [-(width * .5), -(height * .5)]},
10223 fontSize: {to:200, unit: "%"}
10234 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10235 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10236 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10242 // all config options shown with default values
10250 * @param {Object} options (optional) Object literal with any of the Fx config options
10251 * @return {Roo.Element} The Element
10253 switchOff : function(o){
10254 var el = this.getFxEl();
10257 el.queueFx(o, function(){
10258 this.clearOpacity();
10261 // restore values after effect
10262 var r = this.getFxRestore();
10263 var st = this.dom.style;
10265 var after = function(){
10267 el.setDisplayed(false);
10273 el.setPositioning(r.pos);
10274 st.width = r.width;
10275 st.height = r.height;
10280 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10281 this.clearOpacity();
10285 points:{by:[0, this.getHeight() * .5]}
10286 }, o, 'motion', 0.3, 'easeIn', after);
10287 }).defer(100, this);
10294 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10295 * changed using the "attr" config option) and then fading back to the original color. If no original
10296 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10299 // default: highlight background to yellow
10302 // custom: highlight foreground text to blue for 2 seconds
10303 el.highlight("0000ff", { attr: 'color', duration: 2 });
10305 // common config options shown with default values
10306 el.highlight("ffff9c", {
10307 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10308 endColor: (current color) or "ffffff",
10313 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10314 * @param {Object} options (optional) Object literal with any of the Fx config options
10315 * @return {Roo.Element} The Element
10317 highlight : function(color, o){
10318 var el = this.getFxEl();
10321 el.queueFx(o, function(){
10322 color = color || "ffff9c";
10323 attr = o.attr || "backgroundColor";
10325 this.clearOpacity();
10328 var origColor = this.getColor(attr);
10329 var restoreColor = this.dom.style[attr];
10330 endColor = (o.endColor || origColor) || "ffffff";
10332 var after = function(){
10333 el.dom.style[attr] = restoreColor;
10338 a[attr] = {from: color, to: endColor};
10339 arguments.callee.anim = this.fxanim(a,
10349 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10352 // default: a single light blue ripple
10355 // custom: 3 red ripples lasting 3 seconds total
10356 el.frame("ff0000", 3, { duration: 3 });
10358 // common config options shown with default values
10359 el.frame("C3DAF9", 1, {
10360 duration: 1 //duration of entire animation (not each individual ripple)
10361 // Note: Easing is not configurable and will be ignored if included
10364 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10365 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10366 * @param {Object} options (optional) Object literal with any of the Fx config options
10367 * @return {Roo.Element} The Element
10369 frame : function(color, count, o){
10370 var el = this.getFxEl();
10373 el.queueFx(o, function(){
10374 color = color || "#C3DAF9";
10375 if(color.length == 6){
10376 color = "#" + color;
10378 count = count || 1;
10379 duration = o.duration || 1;
10382 var b = this.getBox();
10383 var animFn = function(){
10384 var proxy = this.createProxy({
10387 visbility:"hidden",
10388 position:"absolute",
10389 "z-index":"35000", // yee haw
10390 border:"0px solid " + color
10393 var scale = Roo.isBorderBox ? 2 : 1;
10395 top:{from:b.y, to:b.y - 20},
10396 left:{from:b.x, to:b.x - 20},
10397 borderWidth:{from:0, to:10},
10398 opacity:{from:1, to:0},
10399 height:{from:b.height, to:(b.height + (20*scale))},
10400 width:{from:b.width, to:(b.width + (20*scale))}
10401 }, duration, function(){
10405 animFn.defer((duration/2)*1000, this);
10416 * Creates a pause before any subsequent queued effects begin. If there are
10417 * no effects queued after the pause it will have no effect.
10422 * @param {Number} seconds The length of time to pause (in seconds)
10423 * @return {Roo.Element} The Element
10425 pause : function(seconds){
10426 var el = this.getFxEl();
10429 el.queueFx(o, function(){
10430 setTimeout(function(){
10432 }, seconds * 1000);
10438 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10439 * using the "endOpacity" config option.
10442 // default: fade in from opacity 0 to 100%
10445 // custom: fade in from opacity 0 to 75% over 2 seconds
10446 el.fadeIn({ endOpacity: .75, duration: 2});
10448 // common config options shown with default values
10450 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10455 * @param {Object} options (optional) Object literal with any of the Fx config options
10456 * @return {Roo.Element} The Element
10458 fadeIn : function(o){
10459 var el = this.getFxEl();
10461 el.queueFx(o, function(){
10462 this.setOpacity(0);
10464 this.dom.style.visibility = 'visible';
10465 var to = o.endOpacity || 1;
10466 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10467 o, null, .5, "easeOut", function(){
10469 this.clearOpacity();
10478 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10479 * using the "endOpacity" config option.
10482 // default: fade out from the element's current opacity to 0
10485 // custom: fade out from the element's current opacity to 25% over 2 seconds
10486 el.fadeOut({ endOpacity: .25, duration: 2});
10488 // common config options shown with default values
10490 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10497 * @param {Object} options (optional) Object literal with any of the Fx config options
10498 * @return {Roo.Element} The Element
10500 fadeOut : function(o){
10501 var el = this.getFxEl();
10503 el.queueFx(o, function(){
10504 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10505 o, null, .5, "easeOut", function(){
10506 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10507 this.dom.style.display = "none";
10509 this.dom.style.visibility = "hidden";
10511 this.clearOpacity();
10519 * Animates the transition of an element's dimensions from a starting height/width
10520 * to an ending height/width.
10523 // change height and width to 100x100 pixels
10524 el.scale(100, 100);
10526 // common config options shown with default values. The height and width will default to
10527 // the element's existing values if passed as null.
10530 [element's height], {
10535 * @param {Number} width The new width (pass undefined to keep the original width)
10536 * @param {Number} height The new height (pass undefined to keep the original height)
10537 * @param {Object} options (optional) Object literal with any of the Fx config options
10538 * @return {Roo.Element} The Element
10540 scale : function(w, h, o){
10541 this.shift(Roo.apply({}, o, {
10549 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10550 * Any of these properties not specified in the config object will not be changed. This effect
10551 * requires that at least one new dimension, position or opacity setting must be passed in on
10552 * the config object in order for the function to have any effect.
10555 // slide the element horizontally to x position 200 while changing the height and opacity
10556 el.shift({ x: 200, height: 50, opacity: .8 });
10558 // common config options shown with default values.
10560 width: [element's width],
10561 height: [element's height],
10562 x: [element's x position],
10563 y: [element's y position],
10564 opacity: [element's opacity],
10569 * @param {Object} options Object literal with any of the Fx config options
10570 * @return {Roo.Element} The Element
10572 shift : function(o){
10573 var el = this.getFxEl();
10575 el.queueFx(o, function(){
10576 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10577 if(w !== undefined){
10578 a.width = {to: this.adjustWidth(w)};
10580 if(h !== undefined){
10581 a.height = {to: this.adjustHeight(h)};
10583 if(x !== undefined || y !== undefined){
10585 x !== undefined ? x : this.getX(),
10586 y !== undefined ? y : this.getY()
10589 if(op !== undefined){
10590 a.opacity = {to: op};
10592 if(o.xy !== undefined){
10593 a.points = {to: o.xy};
10595 arguments.callee.anim = this.fxanim(a,
10596 o, 'motion', .35, "easeOut", function(){
10604 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10605 * ending point of the effect.
10608 // default: slide the element downward while fading out
10611 // custom: slide the element out to the right with a 2-second duration
10612 el.ghost('r', { duration: 2 });
10614 // common config options shown with default values
10622 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10623 * @param {Object} options (optional) Object literal with any of the Fx config options
10624 * @return {Roo.Element} The Element
10626 ghost : function(anchor, o){
10627 var el = this.getFxEl();
10630 el.queueFx(o, function(){
10631 anchor = anchor || "b";
10633 // restore values after effect
10634 var r = this.getFxRestore();
10635 var w = this.getWidth(),
10636 h = this.getHeight();
10638 var st = this.dom.style;
10640 var after = function(){
10642 el.setDisplayed(false);
10648 el.setPositioning(r.pos);
10649 st.width = r.width;
10650 st.height = r.height;
10655 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10656 switch(anchor.toLowerCase()){
10683 arguments.callee.anim = this.fxanim(a,
10693 * Ensures that all effects queued after syncFx is called on the element are
10694 * run concurrently. This is the opposite of {@link #sequenceFx}.
10695 * @return {Roo.Element} The Element
10697 syncFx : function(){
10698 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10707 * Ensures that all effects queued after sequenceFx is called on the element are
10708 * run in sequence. This is the opposite of {@link #syncFx}.
10709 * @return {Roo.Element} The Element
10711 sequenceFx : function(){
10712 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10714 concurrent : false,
10721 nextFx : function(){
10722 var ef = this.fxQueue[0];
10729 * Returns true if the element has any effects actively running or queued, else returns false.
10730 * @return {Boolean} True if element has active effects, else false
10732 hasActiveFx : function(){
10733 return this.fxQueue && this.fxQueue[0];
10737 * Stops any running effects and clears the element's internal effects queue if it contains
10738 * any additional effects that haven't started yet.
10739 * @return {Roo.Element} The Element
10741 stopFx : function(){
10742 if(this.hasActiveFx()){
10743 var cur = this.fxQueue[0];
10744 if(cur && cur.anim && cur.anim.isAnimated()){
10745 this.fxQueue = [cur]; // clear out others
10746 cur.anim.stop(true);
10753 beforeFx : function(o){
10754 if(this.hasActiveFx() && !o.concurrent){
10765 * Returns true if the element is currently blocking so that no other effect can be queued
10766 * until this effect is finished, else returns false if blocking is not set. This is commonly
10767 * used to ensure that an effect initiated by a user action runs to completion prior to the
10768 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10769 * @return {Boolean} True if blocking, else false
10771 hasFxBlock : function(){
10772 var q = this.fxQueue;
10773 return q && q[0] && q[0].block;
10777 queueFx : function(o, fn){
10781 if(!this.hasFxBlock()){
10782 Roo.applyIf(o, this.fxDefaults);
10784 var run = this.beforeFx(o);
10785 fn.block = o.block;
10786 this.fxQueue.push(fn);
10798 fxWrap : function(pos, o, vis){
10800 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10803 wrapXY = this.getXY();
10805 var div = document.createElement("div");
10806 div.style.visibility = vis;
10807 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10808 wrap.setPositioning(pos);
10809 if(wrap.getStyle("position") == "static"){
10810 wrap.position("relative");
10812 this.clearPositioning('auto');
10814 wrap.dom.appendChild(this.dom);
10816 wrap.setXY(wrapXY);
10823 fxUnwrap : function(wrap, pos, o){
10824 this.clearPositioning();
10825 this.setPositioning(pos);
10827 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10833 getFxRestore : function(){
10834 var st = this.dom.style;
10835 return {pos: this.getPositioning(), width: st.width, height : st.height};
10839 afterFx : function(o){
10841 this.applyStyles(o.afterStyle);
10844 this.addClass(o.afterCls);
10846 if(o.remove === true){
10849 Roo.callback(o.callback, o.scope, [this]);
10851 this.fxQueue.shift();
10857 getFxEl : function(){ // support for composite element fx
10858 return Roo.get(this.dom);
10862 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10863 animType = animType || 'run';
10865 var anim = Roo.lib.Anim[animType](
10867 (opt.duration || defaultDur) || .35,
10868 (opt.easing || defaultEase) || 'easeOut',
10870 Roo.callback(cb, this);
10879 // backwords compat
10880 Roo.Fx.resize = Roo.Fx.scale;
10882 //When included, Roo.Fx is automatically applied to Element so that all basic
10883 //effects are available directly via the Element API
10884 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10886 * Ext JS Library 1.1.1
10887 * Copyright(c) 2006-2007, Ext JS, LLC.
10889 * Originally Released Under LGPL - original licence link has changed is not relivant.
10892 * <script type="text/javascript">
10897 * @class Roo.CompositeElement
10898 * Standard composite class. Creates a Roo.Element for every element in the collection.
10900 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10901 * actions will be performed on all the elements in this collection.</b>
10903 * All methods return <i>this</i> and can be chained.
10905 var els = Roo.select("#some-el div.some-class", true);
10906 // or select directly from an existing element
10907 var el = Roo.get('some-el');
10908 el.select('div.some-class', true);
10910 els.setWidth(100); // all elements become 100 width
10911 els.hide(true); // all elements fade out and hide
10913 els.setWidth(100).hide(true);
10916 Roo.CompositeElement = function(els){
10917 this.elements = [];
10918 this.addElements(els);
10920 Roo.CompositeElement.prototype = {
10922 addElements : function(els){
10923 if(!els) return this;
10924 if(typeof els == "string"){
10925 els = Roo.Element.selectorFunction(els);
10927 var yels = this.elements;
10928 var index = yels.length-1;
10929 for(var i = 0, len = els.length; i < len; i++) {
10930 yels[++index] = Roo.get(els[i]);
10936 * Clears this composite and adds the elements returned by the passed selector.
10937 * @param {String/Array} els A string CSS selector, an array of elements or an element
10938 * @return {CompositeElement} this
10940 fill : function(els){
10941 this.elements = [];
10947 * Filters this composite to only elements that match the passed selector.
10948 * @param {String} selector A string CSS selector
10949 * @return {CompositeElement} this
10951 filter : function(selector){
10953 this.each(function(el){
10954 if(el.is(selector)){
10955 els[els.length] = el.dom;
10962 invoke : function(fn, args){
10963 var els = this.elements;
10964 for(var i = 0, len = els.length; i < len; i++) {
10965 Roo.Element.prototype[fn].apply(els[i], args);
10970 * Adds elements to this composite.
10971 * @param {String/Array} els A string CSS selector, an array of elements or an element
10972 * @return {CompositeElement} this
10974 add : function(els){
10975 if(typeof els == "string"){
10976 this.addElements(Roo.Element.selectorFunction(els));
10977 }else if(els.length !== undefined){
10978 this.addElements(els);
10980 this.addElements([els]);
10985 * Calls the passed function passing (el, this, index) for each element in this composite.
10986 * @param {Function} fn The function to call
10987 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10988 * @return {CompositeElement} this
10990 each : function(fn, scope){
10991 var els = this.elements;
10992 for(var i = 0, len = els.length; i < len; i++){
10993 if(fn.call(scope || els[i], els[i], this, i) === false) {
11001 * Returns the Element object at the specified index
11002 * @param {Number} index
11003 * @return {Roo.Element}
11005 item : function(index){
11006 return this.elements[index] || null;
11010 * Returns the first Element
11011 * @return {Roo.Element}
11013 first : function(){
11014 return this.item(0);
11018 * Returns the last Element
11019 * @return {Roo.Element}
11022 return this.item(this.elements.length-1);
11026 * Returns the number of elements in this composite
11029 getCount : function(){
11030 return this.elements.length;
11034 * Returns true if this composite contains the passed element
11037 contains : function(el){
11038 return this.indexOf(el) !== -1;
11042 * Returns true if this composite contains the passed element
11045 indexOf : function(el){
11046 return this.elements.indexOf(Roo.get(el));
11051 * Removes the specified element(s).
11052 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11053 * or an array of any of those.
11054 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11055 * @return {CompositeElement} this
11057 removeElement : function(el, removeDom){
11058 if(el instanceof Array){
11059 for(var i = 0, len = el.length; i < len; i++){
11060 this.removeElement(el[i]);
11064 var index = typeof el == 'number' ? el : this.indexOf(el);
11067 var d = this.elements[index];
11071 d.parentNode.removeChild(d);
11074 this.elements.splice(index, 1);
11080 * Replaces the specified element with the passed element.
11081 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11083 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11084 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11085 * @return {CompositeElement} this
11087 replaceElement : function(el, replacement, domReplace){
11088 var index = typeof el == 'number' ? el : this.indexOf(el);
11091 this.elements[index].replaceWith(replacement);
11093 this.elements.splice(index, 1, Roo.get(replacement))
11100 * Removes all elements.
11102 clear : function(){
11103 this.elements = [];
11107 Roo.CompositeElement.createCall = function(proto, fnName){
11108 if(!proto[fnName]){
11109 proto[fnName] = function(){
11110 return this.invoke(fnName, arguments);
11114 for(var fnName in Roo.Element.prototype){
11115 if(typeof Roo.Element.prototype[fnName] == "function"){
11116 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11122 * Ext JS Library 1.1.1
11123 * Copyright(c) 2006-2007, Ext JS, LLC.
11125 * Originally Released Under LGPL - original licence link has changed is not relivant.
11128 * <script type="text/javascript">
11132 * @class Roo.CompositeElementLite
11133 * @extends Roo.CompositeElement
11134 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11136 var els = Roo.select("#some-el div.some-class");
11137 // or select directly from an existing element
11138 var el = Roo.get('some-el');
11139 el.select('div.some-class');
11141 els.setWidth(100); // all elements become 100 width
11142 els.hide(true); // all elements fade out and hide
11144 els.setWidth(100).hide(true);
11145 </code></pre><br><br>
11146 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11147 * actions will be performed on all the elements in this collection.</b>
11149 Roo.CompositeElementLite = function(els){
11150 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11151 this.el = new Roo.Element.Flyweight();
11153 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11154 addElements : function(els){
11156 if(els instanceof Array){
11157 this.elements = this.elements.concat(els);
11159 var yels = this.elements;
11160 var index = yels.length-1;
11161 for(var i = 0, len = els.length; i < len; i++) {
11162 yels[++index] = els[i];
11168 invoke : function(fn, args){
11169 var els = this.elements;
11171 for(var i = 0, len = els.length; i < len; i++) {
11173 Roo.Element.prototype[fn].apply(el, args);
11178 * Returns a flyweight Element of the dom element object at the specified index
11179 * @param {Number} index
11180 * @return {Roo.Element}
11182 item : function(index){
11183 if(!this.elements[index]){
11186 this.el.dom = this.elements[index];
11190 // fixes scope with flyweight
11191 addListener : function(eventName, handler, scope, opt){
11192 var els = this.elements;
11193 for(var i = 0, len = els.length; i < len; i++) {
11194 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11200 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11201 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11202 * a reference to the dom node, use el.dom.</b>
11203 * @param {Function} fn The function to call
11204 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11205 * @return {CompositeElement} this
11207 each : function(fn, scope){
11208 var els = this.elements;
11210 for(var i = 0, len = els.length; i < len; i++){
11212 if(fn.call(scope || el, el, this, i) === false){
11219 indexOf : function(el){
11220 return this.elements.indexOf(Roo.getDom(el));
11223 replaceElement : function(el, replacement, domReplace){
11224 var index = typeof el == 'number' ? el : this.indexOf(el);
11226 replacement = Roo.getDom(replacement);
11228 var d = this.elements[index];
11229 d.parentNode.insertBefore(replacement, d);
11230 d.parentNode.removeChild(d);
11232 this.elements.splice(index, 1, replacement);
11237 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11241 * Ext JS Library 1.1.1
11242 * Copyright(c) 2006-2007, Ext JS, LLC.
11244 * Originally Released Under LGPL - original licence link has changed is not relivant.
11247 * <script type="text/javascript">
11253 * @class Roo.data.Connection
11254 * @extends Roo.util.Observable
11255 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11256 * either to a configured URL, or to a URL specified at request time.<br><br>
11258 * Requests made by this class are asynchronous, and will return immediately. No data from
11259 * the server will be available to the statement immediately following the {@link #request} call.
11260 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11262 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11263 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11264 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11265 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11266 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11267 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11268 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11269 * standard DOM methods.
11271 * @param {Object} config a configuration object.
11273 Roo.data.Connection = function(config){
11274 Roo.apply(this, config);
11277 * @event beforerequest
11278 * Fires before a network request is made to retrieve a data object.
11279 * @param {Connection} conn This Connection object.
11280 * @param {Object} options The options config object passed to the {@link #request} method.
11282 "beforerequest" : true,
11284 * @event requestcomplete
11285 * Fires if the request was successfully completed.
11286 * @param {Connection} conn This Connection object.
11287 * @param {Object} response The XHR object containing the response data.
11288 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11289 * @param {Object} options The options config object passed to the {@link #request} method.
11291 "requestcomplete" : true,
11293 * @event requestexception
11294 * Fires if an error HTTP status was returned from the server.
11295 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11296 * @param {Connection} conn This Connection object.
11297 * @param {Object} response The XHR object containing the response data.
11298 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11299 * @param {Object} options The options config object passed to the {@link #request} method.
11301 "requestexception" : true
11303 Roo.data.Connection.superclass.constructor.call(this);
11306 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11308 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11311 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11312 * extra parameters to each request made by this object. (defaults to undefined)
11315 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11316 * to each request made by this object. (defaults to undefined)
11319 * @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)
11322 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11326 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11332 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11335 disableCaching: true,
11338 * Sends an HTTP request to a remote server.
11339 * @param {Object} options An object which may contain the following properties:<ul>
11340 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11341 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11342 * request, a url encoded string or a function to call to get either.</li>
11343 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11344 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11345 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11346 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11347 * <li>options {Object} The parameter to the request call.</li>
11348 * <li>success {Boolean} True if the request succeeded.</li>
11349 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11351 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11352 * The callback is passed the following parameters:<ul>
11353 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11354 * <li>options {Object} The parameter to the request call.</li>
11356 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11357 * The callback is passed the following parameters:<ul>
11358 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11359 * <li>options {Object} The parameter to the request call.</li>
11361 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11362 * for the callback function. Defaults to the browser window.</li>
11363 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11364 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11365 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11366 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11367 * params for the post data. Any params will be appended to the URL.</li>
11368 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11370 * @return {Number} transactionId
11372 request : function(o){
11373 if(this.fireEvent("beforerequest", this, o) !== false){
11376 if(typeof p == "function"){
11377 p = p.call(o.scope||window, o);
11379 if(typeof p == "object"){
11380 p = Roo.urlEncode(o.params);
11382 if(this.extraParams){
11383 var extras = Roo.urlEncode(this.extraParams);
11384 p = p ? (p + '&' + extras) : extras;
11387 var url = o.url || this.url;
11388 if(typeof url == 'function'){
11389 url = url.call(o.scope||window, o);
11393 var form = Roo.getDom(o.form);
11394 url = url || form.action;
11396 var enctype = form.getAttribute("enctype");
11397 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11398 return this.doFormUpload(o, p, url);
11400 var f = Roo.lib.Ajax.serializeForm(form);
11401 p = p ? (p + '&' + f) : f;
11404 var hs = o.headers;
11405 if(this.defaultHeaders){
11406 hs = Roo.apply(hs || {}, this.defaultHeaders);
11413 success: this.handleResponse,
11414 failure: this.handleFailure,
11416 argument: {options: o},
11417 timeout : o.timeout || this.timeout
11420 var method = o.method||this.method||(p ? "POST" : "GET");
11422 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11423 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11426 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11430 }else if(this.autoAbort !== false){
11434 if((method == 'GET' && p) || o.xmlData){
11435 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11438 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11439 return this.transId;
11441 Roo.callback(o.callback, o.scope, [o, null, null]);
11447 * Determine whether this object has a request outstanding.
11448 * @param {Number} transactionId (Optional) defaults to the last transaction
11449 * @return {Boolean} True if there is an outstanding request.
11451 isLoading : function(transId){
11453 return Roo.lib.Ajax.isCallInProgress(transId);
11455 return this.transId ? true : false;
11460 * Aborts any outstanding request.
11461 * @param {Number} transactionId (Optional) defaults to the last transaction
11463 abort : function(transId){
11464 if(transId || this.isLoading()){
11465 Roo.lib.Ajax.abort(transId || this.transId);
11470 handleResponse : function(response){
11471 this.transId = false;
11472 var options = response.argument.options;
11473 response.argument = options ? options.argument : null;
11474 this.fireEvent("requestcomplete", this, response, options);
11475 Roo.callback(options.success, options.scope, [response, options]);
11476 Roo.callback(options.callback, options.scope, [options, true, response]);
11480 handleFailure : function(response, e){
11481 this.transId = false;
11482 var options = response.argument.options;
11483 response.argument = options ? options.argument : null;
11484 this.fireEvent("requestexception", this, response, options, e);
11485 Roo.callback(options.failure, options.scope, [response, options]);
11486 Roo.callback(options.callback, options.scope, [options, false, response]);
11490 doFormUpload : function(o, ps, url){
11492 var frame = document.createElement('iframe');
11495 frame.className = 'x-hidden';
11497 frame.src = Roo.SSL_SECURE_URL;
11499 document.body.appendChild(frame);
11502 document.frames[id].name = id;
11505 var form = Roo.getDom(o.form);
11507 form.method = 'POST';
11508 form.enctype = form.encoding = 'multipart/form-data';
11514 if(ps){ // add dynamic params
11516 ps = Roo.urlDecode(ps, false);
11518 if(ps.hasOwnProperty(k)){
11519 hd = document.createElement('input');
11520 hd.type = 'hidden';
11523 form.appendChild(hd);
11530 var r = { // bogus response object
11535 r.argument = o ? o.argument : null;
11540 doc = frame.contentWindow.document;
11542 doc = (frame.contentDocument || window.frames[id].document);
11544 if(doc && doc.body){
11545 r.responseText = doc.body.innerHTML;
11547 if(doc && doc.XMLDocument){
11548 r.responseXML = doc.XMLDocument;
11550 r.responseXML = doc;
11557 Roo.EventManager.removeListener(frame, 'load', cb, this);
11559 this.fireEvent("requestcomplete", this, r, o);
11560 Roo.callback(o.success, o.scope, [r, o]);
11561 Roo.callback(o.callback, o.scope, [o, true, r]);
11563 setTimeout(function(){document.body.removeChild(frame);}, 100);
11566 Roo.EventManager.on(frame, 'load', cb, this);
11569 if(hiddens){ // remove dynamic params
11570 for(var i = 0, len = hiddens.length; i < len; i++){
11571 form.removeChild(hiddens[i]);
11578 * Ext JS Library 1.1.1
11579 * Copyright(c) 2006-2007, Ext JS, LLC.
11581 * Originally Released Under LGPL - original licence link has changed is not relivant.
11584 * <script type="text/javascript">
11588 * Global Ajax request class.
11591 * @extends Roo.data.Connection
11594 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11595 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11596 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11597 * @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)
11598 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11599 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11600 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11602 Roo.Ajax = new Roo.data.Connection({
11611 * Serialize the passed form into a url encoded string
11613 * @param {String/HTMLElement} form
11616 serializeForm : function(form){
11617 return Roo.lib.Ajax.serializeForm(form);
11621 * Ext JS Library 1.1.1
11622 * Copyright(c) 2006-2007, Ext JS, LLC.
11624 * Originally Released Under LGPL - original licence link has changed is not relivant.
11627 * <script type="text/javascript">
11632 * @class Roo.UpdateManager
11633 * @extends Roo.util.Observable
11634 * Provides AJAX-style update for Element object.<br><br>
11637 * // Get it from a Roo.Element object
11638 * var el = Roo.get("foo");
11639 * var mgr = el.getUpdateManager();
11640 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11642 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11644 * // or directly (returns the same UpdateManager instance)
11645 * var mgr = new Roo.UpdateManager("myElementId");
11646 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11647 * mgr.on("update", myFcnNeedsToKnow);
11649 // short handed call directly from the element object
11650 Roo.get("foo").load({
11654 text: "Loading Foo..."
11658 * Create new UpdateManager directly.
11659 * @param {String/HTMLElement/Roo.Element} el The element to update
11660 * @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).
11662 Roo.UpdateManager = function(el, forceNew){
11664 if(!forceNew && el.updateManager){
11665 return el.updateManager;
11668 * The Element object
11669 * @type Roo.Element
11673 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11676 this.defaultUrl = null;
11680 * @event beforeupdate
11681 * Fired before an update is made, return false from your handler and the update is cancelled.
11682 * @param {Roo.Element} el
11683 * @param {String/Object/Function} url
11684 * @param {String/Object} params
11686 "beforeupdate": true,
11689 * Fired after successful update is made.
11690 * @param {Roo.Element} el
11691 * @param {Object} oResponseObject The response Object
11696 * Fired on update failure.
11697 * @param {Roo.Element} el
11698 * @param {Object} oResponseObject The response Object
11702 var d = Roo.UpdateManager.defaults;
11704 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11707 this.sslBlankUrl = d.sslBlankUrl;
11709 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11712 this.disableCaching = d.disableCaching;
11714 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11717 this.indicatorText = d.indicatorText;
11719 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11722 this.showLoadIndicator = d.showLoadIndicator;
11724 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11727 this.timeout = d.timeout;
11730 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11733 this.loadScripts = d.loadScripts;
11736 * Transaction object of current executing transaction
11738 this.transaction = null;
11743 this.autoRefreshProcId = null;
11745 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11748 this.refreshDelegate = this.refresh.createDelegate(this);
11750 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11753 this.updateDelegate = this.update.createDelegate(this);
11755 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11758 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11762 this.successDelegate = this.processSuccess.createDelegate(this);
11766 this.failureDelegate = this.processFailure.createDelegate(this);
11768 if(!this.renderer){
11770 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11772 this.renderer = new Roo.UpdateManager.BasicRenderer();
11775 Roo.UpdateManager.superclass.constructor.call(this);
11778 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11780 * Get the Element this UpdateManager is bound to
11781 * @return {Roo.Element} The element
11783 getEl : function(){
11787 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11788 * @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:
11791 url: "your-url.php",<br/>
11792 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11793 callback: yourFunction,<br/>
11794 scope: yourObject, //(optional scope) <br/>
11795 discardUrl: false, <br/>
11796 nocache: false,<br/>
11797 text: "Loading...",<br/>
11799 scripts: false<br/>
11802 * The only required property is url. The optional properties nocache, text and scripts
11803 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11804 * @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}
11805 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11806 * @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.
11808 update : function(url, params, callback, discardUrl){
11809 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11810 var method = this.method,
11812 if(typeof url == "object"){ // must be config object
11815 params = params || cfg.params;
11816 callback = callback || cfg.callback;
11817 discardUrl = discardUrl || cfg.discardUrl;
11818 if(callback && cfg.scope){
11819 callback = callback.createDelegate(cfg.scope);
11821 if(typeof cfg.method != "undefined"){method = cfg.method;};
11822 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11823 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11824 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11825 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11827 this.showLoading();
11829 this.defaultUrl = url;
11831 if(typeof url == "function"){
11832 url = url.call(this);
11835 method = method || (params ? "POST" : "GET");
11836 if(method == "GET"){
11837 url = this.prepareUrl(url);
11840 var o = Roo.apply(cfg ||{}, {
11843 success: this.successDelegate,
11844 failure: this.failureDelegate,
11845 callback: undefined,
11846 timeout: (this.timeout*1000),
11847 argument: {"url": url, "form": null, "callback": callback, "params": params}
11849 Roo.log("updated manager called with timeout of " + o.timeout);
11850 this.transaction = Roo.Ajax.request(o);
11855 * 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.
11856 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11857 * @param {String/HTMLElement} form The form Id or form element
11858 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11859 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11860 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11862 formUpdate : function(form, url, reset, callback){
11863 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11864 if(typeof url == "function"){
11865 url = url.call(this);
11867 form = Roo.getDom(form);
11868 this.transaction = Roo.Ajax.request({
11871 success: this.successDelegate,
11872 failure: this.failureDelegate,
11873 timeout: (this.timeout*1000),
11874 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11876 this.showLoading.defer(1, this);
11881 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11882 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11884 refresh : function(callback){
11885 if(this.defaultUrl == null){
11888 this.update(this.defaultUrl, null, callback, true);
11892 * Set this element to auto refresh.
11893 * @param {Number} interval How often to update (in seconds).
11894 * @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)
11895 * @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}
11896 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11897 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11899 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11901 this.update(url || this.defaultUrl, params, callback, true);
11903 if(this.autoRefreshProcId){
11904 clearInterval(this.autoRefreshProcId);
11906 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11910 * Stop auto refresh on this element.
11912 stopAutoRefresh : function(){
11913 if(this.autoRefreshProcId){
11914 clearInterval(this.autoRefreshProcId);
11915 delete this.autoRefreshProcId;
11919 isAutoRefreshing : function(){
11920 return this.autoRefreshProcId ? true : false;
11923 * Called to update the element to "Loading" state. Override to perform custom action.
11925 showLoading : function(){
11926 if(this.showLoadIndicator){
11927 this.el.update(this.indicatorText);
11932 * Adds unique parameter to query string if disableCaching = true
11935 prepareUrl : function(url){
11936 if(this.disableCaching){
11937 var append = "_dc=" + (new Date().getTime());
11938 if(url.indexOf("?") !== -1){
11939 url += "&" + append;
11941 url += "?" + append;
11950 processSuccess : function(response){
11951 this.transaction = null;
11952 if(response.argument.form && response.argument.reset){
11953 try{ // put in try/catch since some older FF releases had problems with this
11954 response.argument.form.reset();
11957 if(this.loadScripts){
11958 this.renderer.render(this.el, response, this,
11959 this.updateComplete.createDelegate(this, [response]));
11961 this.renderer.render(this.el, response, this);
11962 this.updateComplete(response);
11966 updateComplete : function(response){
11967 this.fireEvent("update", this.el, response);
11968 if(typeof response.argument.callback == "function"){
11969 response.argument.callback(this.el, true, response);
11976 processFailure : function(response){
11977 this.transaction = null;
11978 this.fireEvent("failure", this.el, response);
11979 if(typeof response.argument.callback == "function"){
11980 response.argument.callback(this.el, false, response);
11985 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11986 * @param {Object} renderer The object implementing the render() method
11988 setRenderer : function(renderer){
11989 this.renderer = renderer;
11992 getRenderer : function(){
11993 return this.renderer;
11997 * Set the defaultUrl used for updates
11998 * @param {String/Function} defaultUrl The url or a function to call to get the url
12000 setDefaultUrl : function(defaultUrl){
12001 this.defaultUrl = defaultUrl;
12005 * Aborts the executing transaction
12007 abort : function(){
12008 if(this.transaction){
12009 Roo.Ajax.abort(this.transaction);
12014 * Returns true if an update is in progress
12015 * @return {Boolean}
12017 isUpdating : function(){
12018 if(this.transaction){
12019 return Roo.Ajax.isLoading(this.transaction);
12026 * @class Roo.UpdateManager.defaults
12027 * @static (not really - but it helps the doc tool)
12028 * The defaults collection enables customizing the default properties of UpdateManager
12030 Roo.UpdateManager.defaults = {
12032 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12038 * True to process scripts by default (Defaults to false).
12041 loadScripts : false,
12044 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12047 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12049 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12052 disableCaching : false,
12054 * Whether to show indicatorText when loading (Defaults to true).
12057 showLoadIndicator : true,
12059 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12062 indicatorText : '<div class="loading-indicator">Loading...</div>'
12066 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12068 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12069 * @param {String/HTMLElement/Roo.Element} el The element to update
12070 * @param {String} url The url
12071 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12072 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12075 * @member Roo.UpdateManager
12077 Roo.UpdateManager.updateElement = function(el, url, params, options){
12078 var um = Roo.get(el, true).getUpdateManager();
12079 Roo.apply(um, options);
12080 um.update(url, params, options ? options.callback : null);
12082 // alias for backwards compat
12083 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12085 * @class Roo.UpdateManager.BasicRenderer
12086 * Default Content renderer. Updates the elements innerHTML with the responseText.
12088 Roo.UpdateManager.BasicRenderer = function(){};
12090 Roo.UpdateManager.BasicRenderer.prototype = {
12092 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12093 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12094 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12095 * @param {Roo.Element} el The element being rendered
12096 * @param {Object} response The YUI Connect response object
12097 * @param {UpdateManager} updateManager The calling update manager
12098 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12100 render : function(el, response, updateManager, callback){
12101 el.update(response.responseText, updateManager.loadScripts, callback);
12107 * (c)) Alan Knowles
12113 * @class Roo.DomTemplate
12114 * @extends Roo.Template
12115 * An effort at a dom based template engine..
12117 * Similar to XTemplate, except it uses dom parsing to create the template..
12119 * Supported features:
12124 {a_variable} - output encoded.
12125 {a_variable.format:("Y-m-d")} - call a method on the variable
12126 {a_variable:raw} - unencoded output
12127 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12128 {a_variable:this.method_on_template(...)} - call a method on the template object.
12133 <div roo-for="a_variable or condition.."></div>
12134 <div roo-if="a_variable or condition"></div>
12135 <div roo-exec="some javascript"></div>
12136 <div roo-name="named_template"></div>
12141 Roo.DomTemplate = function()
12143 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12150 Roo.extend(Roo.DomTemplate, Roo.Template, {
12152 * id counter for sub templates.
12156 * flag to indicate if dom parser is inside a pre,
12157 * it will strip whitespace if not.
12162 * The various sub templates
12170 * basic tag replacing syntax
12173 * // you can fake an object call by doing this
12177 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12178 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12180 iterChild : function (node, method) {
12182 var oldPre = this.inPre;
12183 if (node.tagName == 'PRE') {
12186 for( var i = 0; i < node.childNodes.length; i++) {
12187 method.call(this, node.childNodes[i]);
12189 this.inPre = oldPre;
12195 * compile the template
12197 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12200 compile: function()
12204 // covert the html into DOM...
12208 doc = document.implementation.createHTMLDocument("");
12209 doc.documentElement.innerHTML = this.html ;
12210 div = doc.documentElement;
12212 // old IE... - nasty -- it causes all sorts of issues.. with
12213 // images getting pulled from server..
12214 div = document.createElement('div');
12215 div.innerHTML = this.html;
12217 //doc.documentElement.innerHTML = htmlBody
12223 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12225 var tpls = this.tpls;
12227 // create a top level template from the snippet..
12229 //Roo.log(div.innerHTML);
12236 body : div.innerHTML,
12249 Roo.each(tpls, function(tp){
12250 this.compileTpl(tp);
12251 this.tpls[tp.id] = tp;
12254 this.master = tpls[0];
12260 compileNode : function(node, istop) {
12265 // skip anything not a tag..
12266 if (node.nodeType != 1) {
12267 if (node.nodeType == 3 && !this.inPre) {
12268 // reduce white space..
12269 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12292 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12293 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12294 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12295 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12301 // just itterate children..
12302 this.iterChild(node,this.compileNode);
12305 tpl.uid = this.id++;
12306 tpl.value = node.getAttribute('roo-' + tpl.attr);
12307 node.removeAttribute('roo-'+ tpl.attr);
12308 if (tpl.attr != 'name') {
12309 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12310 node.parentNode.replaceChild(placeholder, node);
12313 var placeholder = document.createElement('span');
12314 placeholder.className = 'roo-tpl-' + tpl.value;
12315 node.parentNode.replaceChild(placeholder, node);
12318 // parent now sees '{domtplXXXX}
12319 this.iterChild(node,this.compileNode);
12321 // we should now have node body...
12322 var div = document.createElement('div');
12323 div.appendChild(node);
12325 // this has the unfortunate side effect of converting tagged attributes
12326 // eg. href="{...}" into %7C...%7D
12327 // this has been fixed by searching for those combo's although it's a bit hacky..
12330 tpl.body = div.innerHTML;
12337 switch (tpl.value) {
12338 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12339 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12340 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12345 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12349 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12353 tpl.id = tpl.value; // replace non characters???
12359 this.tpls.push(tpl);
12369 * Compile a segment of the template into a 'sub-template'
12375 compileTpl : function(tpl)
12377 var fm = Roo.util.Format;
12378 var useF = this.disableFormats !== true;
12380 var sep = Roo.isGecko ? "+\n" : ",\n";
12382 var undef = function(str) {
12383 Roo.debug && Roo.log("Property not found :" + str);
12387 //Roo.log(tpl.body);
12391 var fn = function(m, lbrace, name, format, args)
12394 //Roo.log(arguments);
12395 args = args ? args.replace(/\\'/g,"'") : args;
12396 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12397 if (typeof(format) == 'undefined') {
12398 format = 'htmlEncode';
12400 if (format == 'raw' ) {
12404 if(name.substr(0, 6) == 'domtpl'){
12405 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12408 // build an array of options to determine if value is undefined..
12410 // basically get 'xxxx.yyyy' then do
12411 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12412 // (function () { Roo.log("Property not found"); return ''; })() :
12417 Roo.each(name.split('.'), function(st) {
12418 lookfor += (lookfor.length ? '.': '') + st;
12419 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12422 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12425 if(format && useF){
12427 args = args ? ',' + args : "";
12429 if(format.substr(0, 5) != "this."){
12430 format = "fm." + format + '(';
12432 format = 'this.call("'+ format.substr(5) + '", ';
12436 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12439 if (args && args.length) {
12440 // called with xxyx.yuu:(test,test)
12442 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12444 // raw.. - :raw modifier..
12445 return "'"+ sep + udef_st + name + ")"+sep+"'";
12449 // branched to use + in gecko and [].join() in others
12451 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12452 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12455 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12456 body.push(tpl.body.replace(/(\r\n|\n)/g,
12457 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12458 body.push("'].join('');};};");
12459 body = body.join('');
12462 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12464 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12471 * same as applyTemplate, except it's done to one of the subTemplates
12472 * when using named templates, you can do:
12474 * var str = pl.applySubTemplate('your-name', values);
12477 * @param {Number} id of the template
12478 * @param {Object} values to apply to template
12479 * @param {Object} parent (normaly the instance of this object)
12481 applySubTemplate : function(id, values, parent)
12485 var t = this.tpls[id];
12489 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12490 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12494 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12501 if(t.execCall && t.execCall.call(this, values, parent)){
12505 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12511 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12512 parent = t.target ? values : parent;
12513 if(t.forCall && vs instanceof Array){
12515 for(var i = 0, len = vs.length; i < len; i++){
12517 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12519 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12521 //Roo.log(t.compiled);
12525 return buf.join('');
12528 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12533 return t.compiled.call(this, vs, parent);
12535 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12537 //Roo.log(t.compiled);
12545 applyTemplate : function(values){
12546 return this.master.compiled.call(this, values, {});
12547 //var s = this.subs;
12550 apply : function(){
12551 return this.applyTemplate.apply(this, arguments);
12556 Roo.DomTemplate.from = function(el){
12557 el = Roo.getDom(el);
12558 return new Roo.Domtemplate(el.value || el.innerHTML);
12561 * Ext JS Library 1.1.1
12562 * Copyright(c) 2006-2007, Ext JS, LLC.
12564 * Originally Released Under LGPL - original licence link has changed is not relivant.
12567 * <script type="text/javascript">
12571 * @class Roo.util.DelayedTask
12572 * Provides a convenient method of performing setTimeout where a new
12573 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12574 * You can use this class to buffer
12575 * the keypress events for a certain number of milliseconds, and perform only if they stop
12576 * for that amount of time.
12577 * @constructor The parameters to this constructor serve as defaults and are not required.
12578 * @param {Function} fn (optional) The default function to timeout
12579 * @param {Object} scope (optional) The default scope of that timeout
12580 * @param {Array} args (optional) The default Array of arguments
12582 Roo.util.DelayedTask = function(fn, scope, args){
12583 var id = null, d, t;
12585 var call = function(){
12586 var now = new Date().getTime();
12590 fn.apply(scope, args || []);
12594 * Cancels any pending timeout and queues a new one
12595 * @param {Number} delay The milliseconds to delay
12596 * @param {Function} newFn (optional) Overrides function passed to constructor
12597 * @param {Object} newScope (optional) Overrides scope passed to constructor
12598 * @param {Array} newArgs (optional) Overrides args passed to constructor
12600 this.delay = function(delay, newFn, newScope, newArgs){
12601 if(id && delay != d){
12605 t = new Date().getTime();
12607 scope = newScope || scope;
12608 args = newArgs || args;
12610 id = setInterval(call, d);
12615 * Cancel the last queued timeout
12617 this.cancel = function(){
12625 * Ext JS Library 1.1.1
12626 * Copyright(c) 2006-2007, Ext JS, LLC.
12628 * Originally Released Under LGPL - original licence link has changed is not relivant.
12631 * <script type="text/javascript">
12635 Roo.util.TaskRunner = function(interval){
12636 interval = interval || 10;
12637 var tasks = [], removeQueue = [];
12639 var running = false;
12641 var stopThread = function(){
12647 var startThread = function(){
12650 id = setInterval(runTasks, interval);
12654 var removeTask = function(task){
12655 removeQueue.push(task);
12661 var runTasks = function(){
12662 if(removeQueue.length > 0){
12663 for(var i = 0, len = removeQueue.length; i < len; i++){
12664 tasks.remove(removeQueue[i]);
12667 if(tasks.length < 1){
12672 var now = new Date().getTime();
12673 for(var i = 0, len = tasks.length; i < len; ++i){
12675 var itime = now - t.taskRunTime;
12676 if(t.interval <= itime){
12677 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12678 t.taskRunTime = now;
12679 if(rt === false || t.taskRunCount === t.repeat){
12684 if(t.duration && t.duration <= (now - t.taskStartTime)){
12691 * Queues a new task.
12692 * @param {Object} task
12694 this.start = function(task){
12696 task.taskStartTime = new Date().getTime();
12697 task.taskRunTime = 0;
12698 task.taskRunCount = 0;
12703 this.stop = function(task){
12708 this.stopAll = function(){
12710 for(var i = 0, len = tasks.length; i < len; i++){
12711 if(tasks[i].onStop){
12720 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12722 * Ext JS Library 1.1.1
12723 * Copyright(c) 2006-2007, Ext JS, LLC.
12725 * Originally Released Under LGPL - original licence link has changed is not relivant.
12728 * <script type="text/javascript">
12733 * @class Roo.util.MixedCollection
12734 * @extends Roo.util.Observable
12735 * A Collection class that maintains both numeric indexes and keys and exposes events.
12737 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12738 * collection (defaults to false)
12739 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12740 * and return the key value for that item. This is used when available to look up the key on items that
12741 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12742 * equivalent to providing an implementation for the {@link #getKey} method.
12744 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12752 * Fires when the collection is cleared.
12757 * Fires when an item is added to the collection.
12758 * @param {Number} index The index at which the item was added.
12759 * @param {Object} o The item added.
12760 * @param {String} key The key associated with the added item.
12765 * Fires when an item is replaced in the collection.
12766 * @param {String} key he key associated with the new added.
12767 * @param {Object} old The item being replaced.
12768 * @param {Object} new The new item.
12773 * Fires when an item is removed from the collection.
12774 * @param {Object} o The item being removed.
12775 * @param {String} key (optional) The key associated with the removed item.
12780 this.allowFunctions = allowFunctions === true;
12782 this.getKey = keyFn;
12784 Roo.util.MixedCollection.superclass.constructor.call(this);
12787 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12788 allowFunctions : false,
12791 * Adds an item to the collection.
12792 * @param {String} key The key to associate with the item
12793 * @param {Object} o The item to add.
12794 * @return {Object} The item added.
12796 add : function(key, o){
12797 if(arguments.length == 1){
12799 key = this.getKey(o);
12801 if(typeof key == "undefined" || key === null){
12803 this.items.push(o);
12804 this.keys.push(null);
12806 var old = this.map[key];
12808 return this.replace(key, o);
12811 this.items.push(o);
12813 this.keys.push(key);
12815 this.fireEvent("add", this.length-1, o, key);
12820 * MixedCollection has a generic way to fetch keys if you implement getKey.
12823 var mc = new Roo.util.MixedCollection();
12824 mc.add(someEl.dom.id, someEl);
12825 mc.add(otherEl.dom.id, otherEl);
12829 var mc = new Roo.util.MixedCollection();
12830 mc.getKey = function(el){
12836 // or via the constructor
12837 var mc = new Roo.util.MixedCollection(false, function(el){
12843 * @param o {Object} The item for which to find the key.
12844 * @return {Object} The key for the passed item.
12846 getKey : function(o){
12851 * Replaces an item in the collection.
12852 * @param {String} key The key associated with the item to replace, or the item to replace.
12853 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12854 * @return {Object} The new item.
12856 replace : function(key, o){
12857 if(arguments.length == 1){
12859 key = this.getKey(o);
12861 var old = this.item(key);
12862 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12863 return this.add(key, o);
12865 var index = this.indexOfKey(key);
12866 this.items[index] = o;
12868 this.fireEvent("replace", key, old, o);
12873 * Adds all elements of an Array or an Object to the collection.
12874 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12875 * an Array of values, each of which are added to the collection.
12877 addAll : function(objs){
12878 if(arguments.length > 1 || objs instanceof Array){
12879 var args = arguments.length > 1 ? arguments : objs;
12880 for(var i = 0, len = args.length; i < len; i++){
12884 for(var key in objs){
12885 if(this.allowFunctions || typeof objs[key] != "function"){
12886 this.add(key, objs[key]);
12893 * Executes the specified function once for every item in the collection, passing each
12894 * item as the first and only parameter. returning false from the function will stop the iteration.
12895 * @param {Function} fn The function to execute for each item.
12896 * @param {Object} scope (optional) The scope in which to execute the function.
12898 each : function(fn, scope){
12899 var items = [].concat(this.items); // each safe for removal
12900 for(var i = 0, len = items.length; i < len; i++){
12901 if(fn.call(scope || items[i], items[i], i, len) === false){
12908 * Executes the specified function once for every key in the collection, passing each
12909 * key, and its associated item as the first two parameters.
12910 * @param {Function} fn The function to execute for each item.
12911 * @param {Object} scope (optional) The scope in which to execute the function.
12913 eachKey : function(fn, scope){
12914 for(var i = 0, len = this.keys.length; i < len; i++){
12915 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12920 * Returns the first item in the collection which elicits a true return value from the
12921 * passed selection function.
12922 * @param {Function} fn The selection function to execute for each item.
12923 * @param {Object} scope (optional) The scope in which to execute the function.
12924 * @return {Object} The first item in the collection which returned true from the selection function.
12926 find : function(fn, scope){
12927 for(var i = 0, len = this.items.length; i < len; i++){
12928 if(fn.call(scope || window, this.items[i], this.keys[i])){
12929 return this.items[i];
12936 * Inserts an item at the specified index in the collection.
12937 * @param {Number} index The index to insert the item at.
12938 * @param {String} key The key to associate with the new item, or the item itself.
12939 * @param {Object} o (optional) If the second parameter was a key, the new item.
12940 * @return {Object} The item inserted.
12942 insert : function(index, key, o){
12943 if(arguments.length == 2){
12945 key = this.getKey(o);
12947 if(index >= this.length){
12948 return this.add(key, o);
12951 this.items.splice(index, 0, o);
12952 if(typeof key != "undefined" && key != null){
12955 this.keys.splice(index, 0, key);
12956 this.fireEvent("add", index, o, key);
12961 * Removed an item from the collection.
12962 * @param {Object} o The item to remove.
12963 * @return {Object} The item removed.
12965 remove : function(o){
12966 return this.removeAt(this.indexOf(o));
12970 * Remove an item from a specified index in the collection.
12971 * @param {Number} index The index within the collection of the item to remove.
12973 removeAt : function(index){
12974 if(index < this.length && index >= 0){
12976 var o = this.items[index];
12977 this.items.splice(index, 1);
12978 var key = this.keys[index];
12979 if(typeof key != "undefined"){
12980 delete this.map[key];
12982 this.keys.splice(index, 1);
12983 this.fireEvent("remove", o, key);
12988 * Removed an item associated with the passed key fom the collection.
12989 * @param {String} key The key of the item to remove.
12991 removeKey : function(key){
12992 return this.removeAt(this.indexOfKey(key));
12996 * Returns the number of items in the collection.
12997 * @return {Number} the number of items in the collection.
12999 getCount : function(){
13000 return this.length;
13004 * Returns index within the collection of the passed Object.
13005 * @param {Object} o The item to find the index of.
13006 * @return {Number} index of the item.
13008 indexOf : function(o){
13009 if(!this.items.indexOf){
13010 for(var i = 0, len = this.items.length; i < len; i++){
13011 if(this.items[i] == o) return i;
13015 return this.items.indexOf(o);
13020 * Returns index within the collection of the passed key.
13021 * @param {String} key The key to find the index of.
13022 * @return {Number} index of the key.
13024 indexOfKey : function(key){
13025 if(!this.keys.indexOf){
13026 for(var i = 0, len = this.keys.length; i < len; i++){
13027 if(this.keys[i] == key) return i;
13031 return this.keys.indexOf(key);
13036 * Returns the item associated with the passed key OR index. Key has priority over index.
13037 * @param {String/Number} key The key or index of the item.
13038 * @return {Object} The item associated with the passed key.
13040 item : function(key){
13041 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13042 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13046 * Returns the item at the specified index.
13047 * @param {Number} index The index of the item.
13050 itemAt : function(index){
13051 return this.items[index];
13055 * Returns the item associated with the passed key.
13056 * @param {String/Number} key The key of the item.
13057 * @return {Object} The item associated with the passed key.
13059 key : function(key){
13060 return this.map[key];
13064 * Returns true if the collection contains the passed Object as an item.
13065 * @param {Object} o The Object to look for in the collection.
13066 * @return {Boolean} True if the collection contains the Object as an item.
13068 contains : function(o){
13069 return this.indexOf(o) != -1;
13073 * Returns true if the collection contains the passed Object as a key.
13074 * @param {String} key The key to look for in the collection.
13075 * @return {Boolean} True if the collection contains the Object as a key.
13077 containsKey : function(key){
13078 return typeof this.map[key] != "undefined";
13082 * Removes all items from the collection.
13084 clear : function(){
13089 this.fireEvent("clear");
13093 * Returns the first item in the collection.
13094 * @return {Object} the first item in the collection..
13096 first : function(){
13097 return this.items[0];
13101 * Returns the last item in the collection.
13102 * @return {Object} the last item in the collection..
13105 return this.items[this.length-1];
13108 _sort : function(property, dir, fn){
13109 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13110 fn = fn || function(a, b){
13113 var c = [], k = this.keys, items = this.items;
13114 for(var i = 0, len = items.length; i < len; i++){
13115 c[c.length] = {key: k[i], value: items[i], index: i};
13117 c.sort(function(a, b){
13118 var v = fn(a[property], b[property]) * dsc;
13120 v = (a.index < b.index ? -1 : 1);
13124 for(var i = 0, len = c.length; i < len; i++){
13125 items[i] = c[i].value;
13128 this.fireEvent("sort", this);
13132 * Sorts this collection with the passed comparison function
13133 * @param {String} direction (optional) "ASC" or "DESC"
13134 * @param {Function} fn (optional) comparison function
13136 sort : function(dir, fn){
13137 this._sort("value", dir, fn);
13141 * Sorts this collection by keys
13142 * @param {String} direction (optional) "ASC" or "DESC"
13143 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13145 keySort : function(dir, fn){
13146 this._sort("key", dir, fn || function(a, b){
13147 return String(a).toUpperCase()-String(b).toUpperCase();
13152 * Returns a range of items in this collection
13153 * @param {Number} startIndex (optional) defaults to 0
13154 * @param {Number} endIndex (optional) default to the last item
13155 * @return {Array} An array of items
13157 getRange : function(start, end){
13158 var items = this.items;
13159 if(items.length < 1){
13162 start = start || 0;
13163 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13166 for(var i = start; i <= end; i++) {
13167 r[r.length] = items[i];
13170 for(var i = start; i >= end; i--) {
13171 r[r.length] = items[i];
13178 * Filter the <i>objects</i> in this collection by a specific property.
13179 * Returns a new collection that has been filtered.
13180 * @param {String} property A property on your objects
13181 * @param {String/RegExp} value Either string that the property values
13182 * should start with or a RegExp to test against the property
13183 * @return {MixedCollection} The new filtered collection
13185 filter : function(property, value){
13186 if(!value.exec){ // not a regex
13187 value = String(value);
13188 if(value.length == 0){
13189 return this.clone();
13191 value = new RegExp("^" + Roo.escapeRe(value), "i");
13193 return this.filterBy(function(o){
13194 return o && value.test(o[property]);
13199 * Filter by a function. * Returns a new collection that has been filtered.
13200 * The passed function will be called with each
13201 * object in the collection. If the function returns true, the value is included
13202 * otherwise it is filtered.
13203 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13204 * @param {Object} scope (optional) The scope of the function (defaults to this)
13205 * @return {MixedCollection} The new filtered collection
13207 filterBy : function(fn, scope){
13208 var r = new Roo.util.MixedCollection();
13209 r.getKey = this.getKey;
13210 var k = this.keys, it = this.items;
13211 for(var i = 0, len = it.length; i < len; i++){
13212 if(fn.call(scope||this, it[i], k[i])){
13213 r.add(k[i], it[i]);
13220 * Creates a duplicate of this collection
13221 * @return {MixedCollection}
13223 clone : function(){
13224 var r = new Roo.util.MixedCollection();
13225 var k = this.keys, it = this.items;
13226 for(var i = 0, len = it.length; i < len; i++){
13227 r.add(k[i], it[i]);
13229 r.getKey = this.getKey;
13234 * Returns the item associated with the passed key or index.
13236 * @param {String/Number} key The key or index of the item.
13237 * @return {Object} The item associated with the passed key.
13239 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13241 * Ext JS Library 1.1.1
13242 * Copyright(c) 2006-2007, Ext JS, LLC.
13244 * Originally Released Under LGPL - original licence link has changed is not relivant.
13247 * <script type="text/javascript">
13250 * @class Roo.util.JSON
13251 * Modified version of Douglas Crockford"s json.js that doesn"t
13252 * mess with the Object prototype
13253 * http://www.json.org/js.html
13256 Roo.util.JSON = new (function(){
13257 var useHasOwn = {}.hasOwnProperty ? true : false;
13259 // crashes Safari in some instances
13260 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13262 var pad = function(n) {
13263 return n < 10 ? "0" + n : n;
13276 var encodeString = function(s){
13277 if (/["\\\x00-\x1f]/.test(s)) {
13278 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13283 c = b.charCodeAt();
13285 Math.floor(c / 16).toString(16) +
13286 (c % 16).toString(16);
13289 return '"' + s + '"';
13292 var encodeArray = function(o){
13293 var a = ["["], b, i, l = o.length, v;
13294 for (i = 0; i < l; i += 1) {
13296 switch (typeof v) {
13305 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13313 var encodeDate = function(o){
13314 return '"' + o.getFullYear() + "-" +
13315 pad(o.getMonth() + 1) + "-" +
13316 pad(o.getDate()) + "T" +
13317 pad(o.getHours()) + ":" +
13318 pad(o.getMinutes()) + ":" +
13319 pad(o.getSeconds()) + '"';
13323 * Encodes an Object, Array or other value
13324 * @param {Mixed} o The variable to encode
13325 * @return {String} The JSON string
13327 this.encode = function(o)
13329 // should this be extended to fully wrap stringify..
13331 if(typeof o == "undefined" || o === null){
13333 }else if(o instanceof Array){
13334 return encodeArray(o);
13335 }else if(o instanceof Date){
13336 return encodeDate(o);
13337 }else if(typeof o == "string"){
13338 return encodeString(o);
13339 }else if(typeof o == "number"){
13340 return isFinite(o) ? String(o) : "null";
13341 }else if(typeof o == "boolean"){
13344 var a = ["{"], b, i, v;
13346 if(!useHasOwn || o.hasOwnProperty(i)) {
13348 switch (typeof v) {
13357 a.push(this.encode(i), ":",
13358 v === null ? "null" : this.encode(v));
13369 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13370 * @param {String} json The JSON string
13371 * @return {Object} The resulting object
13373 this.decode = function(json){
13375 return /** eval:var:json */ eval("(" + json + ')');
13379 * Shorthand for {@link Roo.util.JSON#encode}
13380 * @member Roo encode
13382 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13384 * Shorthand for {@link Roo.util.JSON#decode}
13385 * @member Roo decode
13387 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13390 * Ext JS Library 1.1.1
13391 * Copyright(c) 2006-2007, Ext JS, LLC.
13393 * Originally Released Under LGPL - original licence link has changed is not relivant.
13396 * <script type="text/javascript">
13400 * @class Roo.util.Format
13401 * Reusable data formatting functions
13404 Roo.util.Format = function(){
13405 var trimRe = /^\s+|\s+$/g;
13408 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13409 * @param {String} value The string to truncate
13410 * @param {Number} length The maximum length to allow before truncating
13411 * @return {String} The converted text
13413 ellipsis : function(value, len){
13414 if(value && value.length > len){
13415 return value.substr(0, len-3)+"...";
13421 * Checks a reference and converts it to empty string if it is undefined
13422 * @param {Mixed} value Reference to check
13423 * @return {Mixed} Empty string if converted, otherwise the original value
13425 undef : function(value){
13426 return typeof value != "undefined" ? value : "";
13430 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13431 * @param {String} value The string to encode
13432 * @return {String} The encoded text
13434 htmlEncode : function(value){
13435 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13439 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13440 * @param {String} value The string to decode
13441 * @return {String} The decoded text
13443 htmlDecode : function(value){
13444 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13448 * Trims any whitespace from either side of a string
13449 * @param {String} value The text to trim
13450 * @return {String} The trimmed text
13452 trim : function(value){
13453 return String(value).replace(trimRe, "");
13457 * Returns a substring from within an original string
13458 * @param {String} value The original text
13459 * @param {Number} start The start index of the substring
13460 * @param {Number} length The length of the substring
13461 * @return {String} The substring
13463 substr : function(value, start, length){
13464 return String(value).substr(start, length);
13468 * Converts a string to all lower case letters
13469 * @param {String} value The text to convert
13470 * @return {String} The converted text
13472 lowercase : function(value){
13473 return String(value).toLowerCase();
13477 * Converts a string to all upper case letters
13478 * @param {String} value The text to convert
13479 * @return {String} The converted text
13481 uppercase : function(value){
13482 return String(value).toUpperCase();
13486 * Converts the first character only of a string to upper case
13487 * @param {String} value The text to convert
13488 * @return {String} The converted text
13490 capitalize : function(value){
13491 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13495 call : function(value, fn){
13496 if(arguments.length > 2){
13497 var args = Array.prototype.slice.call(arguments, 2);
13498 args.unshift(value);
13500 return /** eval:var:value */ eval(fn).apply(window, args);
13502 /** eval:var:value */
13503 return /** eval:var:value */ eval(fn).call(window, value);
13509 * safer version of Math.toFixed..??/
13510 * @param {Number/String} value The numeric value to format
13511 * @param {Number/String} value Decimal places
13512 * @return {String} The formatted currency string
13514 toFixed : function(v, n)
13516 // why not use to fixed - precision is buggered???
13518 return Math.round(v-0);
13520 var fact = Math.pow(10,n+1);
13521 v = (Math.round((v-0)*fact))/fact;
13522 var z = (''+fact).substring(2);
13523 if (v == Math.floor(v)) {
13524 return Math.floor(v) + '.' + z;
13527 // now just padd decimals..
13528 var ps = String(v).split('.');
13529 var fd = (ps[1] + z);
13530 var r = fd.substring(0,n);
13531 var rm = fd.substring(n);
13533 return ps[0] + '.' + r;
13535 r*=1; // turn it into a number;
13537 if (String(r).length != n) {
13540 r = String(r).substring(1); // chop the end off.
13543 return ps[0] + '.' + r;
13548 * Format a number as US currency
13549 * @param {Number/String} value The numeric value to format
13550 * @return {String} The formatted currency string
13552 usMoney : function(v){
13553 return '$' + Roo.util.Format.number(v);
13558 * eventually this should probably emulate php's number_format
13559 * @param {Number/String} value The numeric value to format
13560 * @param {Number} decimals number of decimal places
13561 * @return {String} The formatted currency string
13563 number : function(v,decimals)
13565 // multiply and round.
13566 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13567 var mul = Math.pow(10, decimals);
13568 var zero = String(mul).substring(1);
13569 v = (Math.round((v-0)*mul))/mul;
13571 // if it's '0' number.. then
13573 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13575 var ps = v.split('.');
13579 var r = /(\d+)(\d{3})/;
13581 while (r.test(whole)) {
13582 whole = whole.replace(r, '$1' + ',' + '$2');
13588 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13589 // does not have decimals
13590 (decimals ? ('.' + zero) : '');
13593 return whole + sub ;
13597 * Parse a value into a formatted date using the specified format pattern.
13598 * @param {Mixed} value The value to format
13599 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13600 * @return {String} The formatted date string
13602 date : function(v, format){
13606 if(!(v instanceof Date)){
13607 v = new Date(Date.parse(v));
13609 return v.dateFormat(format || "m/d/Y");
13613 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13614 * @param {String} format Any valid date format string
13615 * @return {Function} The date formatting function
13617 dateRenderer : function(format){
13618 return function(v){
13619 return Roo.util.Format.date(v, format);
13624 stripTagsRE : /<\/?[^>]+>/gi,
13627 * Strips all HTML tags
13628 * @param {Mixed} value The text from which to strip tags
13629 * @return {String} The stripped text
13631 stripTags : function(v){
13632 return !v ? v : String(v).replace(this.stripTagsRE, "");
13637 * Ext JS Library 1.1.1
13638 * Copyright(c) 2006-2007, Ext JS, LLC.
13640 * Originally Released Under LGPL - original licence link has changed is not relivant.
13643 * <script type="text/javascript">
13650 * @class Roo.MasterTemplate
13651 * @extends Roo.Template
13652 * Provides a template that can have child templates. The syntax is:
13654 var t = new Roo.MasterTemplate(
13655 '<select name="{name}">',
13656 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13659 t.add('options', {value: 'foo', text: 'bar'});
13660 // or you can add multiple child elements in one shot
13661 t.addAll('options', [
13662 {value: 'foo', text: 'bar'},
13663 {value: 'foo2', text: 'bar2'},
13664 {value: 'foo3', text: 'bar3'}
13666 // then append, applying the master template values
13667 t.append('my-form', {name: 'my-select'});
13669 * A name attribute for the child template is not required if you have only one child
13670 * template or you want to refer to them by index.
13672 Roo.MasterTemplate = function(){
13673 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13674 this.originalHtml = this.html;
13676 var m, re = this.subTemplateRe;
13679 while(m = re.exec(this.html)){
13680 var name = m[1], content = m[2];
13685 tpl : new Roo.Template(content)
13688 st[name] = st[subIndex];
13690 st[subIndex].tpl.compile();
13691 st[subIndex].tpl.call = this.call.createDelegate(this);
13694 this.subCount = subIndex;
13697 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13699 * The regular expression used to match sub templates
13703 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13706 * Applies the passed values to a child template.
13707 * @param {String/Number} name (optional) The name or index of the child template
13708 * @param {Array/Object} values The values to be applied to the template
13709 * @return {MasterTemplate} this
13711 add : function(name, values){
13712 if(arguments.length == 1){
13713 values = arguments[0];
13716 var s = this.subs[name];
13717 s.buffer[s.buffer.length] = s.tpl.apply(values);
13722 * Applies all the passed values to a child template.
13723 * @param {String/Number} name (optional) The name or index of the child template
13724 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13725 * @param {Boolean} reset (optional) True to reset the template first
13726 * @return {MasterTemplate} this
13728 fill : function(name, values, reset){
13730 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13738 for(var i = 0, len = values.length; i < len; i++){
13739 this.add(name, values[i]);
13745 * Resets the template for reuse
13746 * @return {MasterTemplate} this
13748 reset : function(){
13750 for(var i = 0; i < this.subCount; i++){
13756 applyTemplate : function(values){
13758 var replaceIndex = -1;
13759 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13760 return s[++replaceIndex].buffer.join("");
13762 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13765 apply : function(){
13766 return this.applyTemplate.apply(this, arguments);
13769 compile : function(){return this;}
13773 * Alias for fill().
13776 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13778 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13779 * var tpl = Roo.MasterTemplate.from('element-id');
13780 * @param {String/HTMLElement} el
13781 * @param {Object} config
13784 Roo.MasterTemplate.from = function(el, config){
13785 el = Roo.getDom(el);
13786 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13789 * Ext JS Library 1.1.1
13790 * Copyright(c) 2006-2007, Ext JS, LLC.
13792 * Originally Released Under LGPL - original licence link has changed is not relivant.
13795 * <script type="text/javascript">
13800 * @class Roo.util.CSS
13801 * Utility class for manipulating CSS rules
13804 Roo.util.CSS = function(){
13806 var doc = document;
13808 var camelRe = /(-[a-z])/gi;
13809 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13813 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13814 * tag and appended to the HEAD of the document.
13815 * @param {String|Object} cssText The text containing the css rules
13816 * @param {String} id An id to add to the stylesheet for later removal
13817 * @return {StyleSheet}
13819 createStyleSheet : function(cssText, id){
13821 var head = doc.getElementsByTagName("head")[0];
13822 var nrules = doc.createElement("style");
13823 nrules.setAttribute("type", "text/css");
13825 nrules.setAttribute("id", id);
13827 if (typeof(cssText) != 'string') {
13828 // support object maps..
13829 // not sure if this a good idea..
13830 // perhaps it should be merged with the general css handling
13831 // and handle js style props.
13832 var cssTextNew = [];
13833 for(var n in cssText) {
13835 for(var k in cssText[n]) {
13836 citems.push( k + ' : ' +cssText[n][k] + ';' );
13838 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13841 cssText = cssTextNew.join("\n");
13847 head.appendChild(nrules);
13848 ss = nrules.styleSheet;
13849 ss.cssText = cssText;
13852 nrules.appendChild(doc.createTextNode(cssText));
13854 nrules.cssText = cssText;
13856 head.appendChild(nrules);
13857 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13859 this.cacheStyleSheet(ss);
13864 * Removes a style or link tag by id
13865 * @param {String} id The id of the tag
13867 removeStyleSheet : function(id){
13868 var existing = doc.getElementById(id);
13870 existing.parentNode.removeChild(existing);
13875 * Dynamically swaps an existing stylesheet reference for a new one
13876 * @param {String} id The id of an existing link tag to remove
13877 * @param {String} url The href of the new stylesheet to include
13879 swapStyleSheet : function(id, url){
13880 this.removeStyleSheet(id);
13881 var ss = doc.createElement("link");
13882 ss.setAttribute("rel", "stylesheet");
13883 ss.setAttribute("type", "text/css");
13884 ss.setAttribute("id", id);
13885 ss.setAttribute("href", url);
13886 doc.getElementsByTagName("head")[0].appendChild(ss);
13890 * Refresh the rule cache if you have dynamically added stylesheets
13891 * @return {Object} An object (hash) of rules indexed by selector
13893 refreshCache : function(){
13894 return this.getRules(true);
13898 cacheStyleSheet : function(stylesheet){
13902 try{// try catch for cross domain access issue
13903 var ssRules = stylesheet.cssRules || stylesheet.rules;
13904 for(var j = ssRules.length-1; j >= 0; --j){
13905 rules[ssRules[j].selectorText] = ssRules[j];
13911 * Gets all css rules for the document
13912 * @param {Boolean} refreshCache true to refresh the internal cache
13913 * @return {Object} An object (hash) of rules indexed by selector
13915 getRules : function(refreshCache){
13916 if(rules == null || refreshCache){
13918 var ds = doc.styleSheets;
13919 for(var i =0, len = ds.length; i < len; i++){
13921 this.cacheStyleSheet(ds[i]);
13929 * Gets an an individual CSS rule by selector(s)
13930 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13931 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13932 * @return {CSSRule} The CSS rule or null if one is not found
13934 getRule : function(selector, refreshCache){
13935 var rs = this.getRules(refreshCache);
13936 if(!(selector instanceof Array)){
13937 return rs[selector];
13939 for(var i = 0; i < selector.length; i++){
13940 if(rs[selector[i]]){
13941 return rs[selector[i]];
13949 * Updates a rule property
13950 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13951 * @param {String} property The css property
13952 * @param {String} value The new value for the property
13953 * @return {Boolean} true If a rule was found and updated
13955 updateRule : function(selector, property, value){
13956 if(!(selector instanceof Array)){
13957 var rule = this.getRule(selector);
13959 rule.style[property.replace(camelRe, camelFn)] = value;
13963 for(var i = 0; i < selector.length; i++){
13964 if(this.updateRule(selector[i], property, value)){
13974 * Ext JS Library 1.1.1
13975 * Copyright(c) 2006-2007, Ext JS, LLC.
13977 * Originally Released Under LGPL - original licence link has changed is not relivant.
13980 * <script type="text/javascript">
13986 * @class Roo.util.ClickRepeater
13987 * @extends Roo.util.Observable
13989 * A wrapper class which can be applied to any element. Fires a "click" event while the
13990 * mouse is pressed. The interval between firings may be specified in the config but
13991 * defaults to 10 milliseconds.
13993 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13995 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13996 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13997 * Similar to an autorepeat key delay.
13998 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13999 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14000 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14001 * "interval" and "delay" are ignored. "immediate" is honored.
14002 * @cfg {Boolean} preventDefault True to prevent the default click event
14003 * @cfg {Boolean} stopDefault True to stop the default click event
14006 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14007 * 2007-02-02 jvs Renamed to ClickRepeater
14008 * 2007-02-03 jvs Modifications for FF Mac and Safari
14011 * @param {String/HTMLElement/Element} el The element to listen on
14012 * @param {Object} config
14014 Roo.util.ClickRepeater = function(el, config)
14016 this.el = Roo.get(el);
14017 this.el.unselectable();
14019 Roo.apply(this, config);
14024 * Fires when the mouse button is depressed.
14025 * @param {Roo.util.ClickRepeater} this
14027 "mousedown" : true,
14030 * Fires on a specified interval during the time the element is pressed.
14031 * @param {Roo.util.ClickRepeater} this
14036 * Fires when the mouse key is released.
14037 * @param {Roo.util.ClickRepeater} this
14042 this.el.on("mousedown", this.handleMouseDown, this);
14043 if(this.preventDefault || this.stopDefault){
14044 this.el.on("click", function(e){
14045 if(this.preventDefault){
14046 e.preventDefault();
14048 if(this.stopDefault){
14054 // allow inline handler
14056 this.on("click", this.handler, this.scope || this);
14059 Roo.util.ClickRepeater.superclass.constructor.call(this);
14062 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14065 preventDefault : true,
14066 stopDefault : false,
14070 handleMouseDown : function(){
14071 clearTimeout(this.timer);
14073 if(this.pressClass){
14074 this.el.addClass(this.pressClass);
14076 this.mousedownTime = new Date();
14078 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14079 this.el.on("mouseout", this.handleMouseOut, this);
14081 this.fireEvent("mousedown", this);
14082 this.fireEvent("click", this);
14084 this.timer = this.click.defer(this.delay || this.interval, this);
14088 click : function(){
14089 this.fireEvent("click", this);
14090 this.timer = this.click.defer(this.getInterval(), this);
14094 getInterval: function(){
14095 if(!this.accelerate){
14096 return this.interval;
14098 var pressTime = this.mousedownTime.getElapsed();
14099 if(pressTime < 500){
14101 }else if(pressTime < 1700){
14103 }else if(pressTime < 2600){
14105 }else if(pressTime < 3500){
14107 }else if(pressTime < 4400){
14109 }else if(pressTime < 5300){
14111 }else if(pressTime < 6200){
14119 handleMouseOut : function(){
14120 clearTimeout(this.timer);
14121 if(this.pressClass){
14122 this.el.removeClass(this.pressClass);
14124 this.el.on("mouseover", this.handleMouseReturn, this);
14128 handleMouseReturn : function(){
14129 this.el.un("mouseover", this.handleMouseReturn);
14130 if(this.pressClass){
14131 this.el.addClass(this.pressClass);
14137 handleMouseUp : function(){
14138 clearTimeout(this.timer);
14139 this.el.un("mouseover", this.handleMouseReturn);
14140 this.el.un("mouseout", this.handleMouseOut);
14141 Roo.get(document).un("mouseup", this.handleMouseUp);
14142 this.el.removeClass(this.pressClass);
14143 this.fireEvent("mouseup", this);
14147 * Ext JS Library 1.1.1
14148 * Copyright(c) 2006-2007, Ext JS, LLC.
14150 * Originally Released Under LGPL - original licence link has changed is not relivant.
14153 * <script type="text/javascript">
14158 * @class Roo.KeyNav
14159 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14160 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14161 * way to implement custom navigation schemes for any UI component.</p>
14162 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14163 * pageUp, pageDown, del, home, end. Usage:</p>
14165 var nav = new Roo.KeyNav("my-element", {
14166 "left" : function(e){
14167 this.moveLeft(e.ctrlKey);
14169 "right" : function(e){
14170 this.moveRight(e.ctrlKey);
14172 "enter" : function(e){
14179 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14180 * @param {Object} config The config
14182 Roo.KeyNav = function(el, config){
14183 this.el = Roo.get(el);
14184 Roo.apply(this, config);
14185 if(!this.disabled){
14186 this.disabled = true;
14191 Roo.KeyNav.prototype = {
14193 * @cfg {Boolean} disabled
14194 * True to disable this KeyNav instance (defaults to false)
14198 * @cfg {String} defaultEventAction
14199 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14200 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14201 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14203 defaultEventAction: "stopEvent",
14205 * @cfg {Boolean} forceKeyDown
14206 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14207 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14208 * handle keydown instead of keypress.
14210 forceKeyDown : false,
14213 prepareEvent : function(e){
14214 var k = e.getKey();
14215 var h = this.keyToHandler[k];
14216 //if(h && this[h]){
14217 // e.stopPropagation();
14219 if(Roo.isSafari && h && k >= 37 && k <= 40){
14225 relay : function(e){
14226 var k = e.getKey();
14227 var h = this.keyToHandler[k];
14229 if(this.doRelay(e, this[h], h) !== true){
14230 e[this.defaultEventAction]();
14236 doRelay : function(e, h, hname){
14237 return h.call(this.scope || this, e);
14240 // possible handlers
14254 // quick lookup hash
14271 * Enable this KeyNav
14273 enable: function(){
14275 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14276 // the EventObject will normalize Safari automatically
14277 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14278 this.el.on("keydown", this.relay, this);
14280 this.el.on("keydown", this.prepareEvent, this);
14281 this.el.on("keypress", this.relay, this);
14283 this.disabled = false;
14288 * Disable this KeyNav
14290 disable: function(){
14291 if(!this.disabled){
14292 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14293 this.el.un("keydown", this.relay);
14295 this.el.un("keydown", this.prepareEvent);
14296 this.el.un("keypress", this.relay);
14298 this.disabled = true;
14303 * Ext JS Library 1.1.1
14304 * Copyright(c) 2006-2007, Ext JS, LLC.
14306 * Originally Released Under LGPL - original licence link has changed is not relivant.
14309 * <script type="text/javascript">
14314 * @class Roo.KeyMap
14315 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14316 * The constructor accepts the same config object as defined by {@link #addBinding}.
14317 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14318 * combination it will call the function with this signature (if the match is a multi-key
14319 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14320 * A KeyMap can also handle a string representation of keys.<br />
14323 // map one key by key code
14324 var map = new Roo.KeyMap("my-element", {
14325 key: 13, // or Roo.EventObject.ENTER
14330 // map multiple keys to one action by string
14331 var map = new Roo.KeyMap("my-element", {
14337 // map multiple keys to multiple actions by strings and array of codes
14338 var map = new Roo.KeyMap("my-element", [
14341 fn: function(){ alert("Return was pressed"); }
14344 fn: function(){ alert('a, b or c was pressed'); }
14349 fn: function(){ alert('Control + shift + tab was pressed.'); }
14353 * <b>Note: A KeyMap starts enabled</b>
14355 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14356 * @param {Object} config The config (see {@link #addBinding})
14357 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14359 Roo.KeyMap = function(el, config, eventName){
14360 this.el = Roo.get(el);
14361 this.eventName = eventName || "keydown";
14362 this.bindings = [];
14364 this.addBinding(config);
14369 Roo.KeyMap.prototype = {
14371 * True to stop the event from bubbling and prevent the default browser action if the
14372 * key was handled by the KeyMap (defaults to false)
14378 * Add a new binding to this KeyMap. The following config object properties are supported:
14380 Property Type Description
14381 ---------- --------------- ----------------------------------------------------------------------
14382 key String/Array A single keycode or an array of keycodes to handle
14383 shift Boolean True to handle key only when shift is pressed (defaults to false)
14384 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14385 alt Boolean True to handle key only when alt is pressed (defaults to false)
14386 fn Function The function to call when KeyMap finds the expected key combination
14387 scope Object The scope of the callback function
14393 var map = new Roo.KeyMap(document, {
14394 key: Roo.EventObject.ENTER,
14399 //Add a new binding to the existing KeyMap later
14407 * @param {Object/Array} config A single KeyMap config or an array of configs
14409 addBinding : function(config){
14410 if(config instanceof Array){
14411 for(var i = 0, len = config.length; i < len; i++){
14412 this.addBinding(config[i]);
14416 var keyCode = config.key,
14417 shift = config.shift,
14418 ctrl = config.ctrl,
14421 scope = config.scope;
14422 if(typeof keyCode == "string"){
14424 var keyString = keyCode.toUpperCase();
14425 for(var j = 0, len = keyString.length; j < len; j++){
14426 ks.push(keyString.charCodeAt(j));
14430 var keyArray = keyCode instanceof Array;
14431 var handler = function(e){
14432 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14433 var k = e.getKey();
14435 for(var i = 0, len = keyCode.length; i < len; i++){
14436 if(keyCode[i] == k){
14437 if(this.stopEvent){
14440 fn.call(scope || window, k, e);
14446 if(this.stopEvent){
14449 fn.call(scope || window, k, e);
14454 this.bindings.push(handler);
14458 * Shorthand for adding a single key listener
14459 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14460 * following options:
14461 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14462 * @param {Function} fn The function to call
14463 * @param {Object} scope (optional) The scope of the function
14465 on : function(key, fn, scope){
14466 var keyCode, shift, ctrl, alt;
14467 if(typeof key == "object" && !(key instanceof Array)){
14486 handleKeyDown : function(e){
14487 if(this.enabled){ //just in case
14488 var b = this.bindings;
14489 for(var i = 0, len = b.length; i < len; i++){
14490 b[i].call(this, e);
14496 * Returns true if this KeyMap is enabled
14497 * @return {Boolean}
14499 isEnabled : function(){
14500 return this.enabled;
14504 * Enables this KeyMap
14506 enable: function(){
14508 this.el.on(this.eventName, this.handleKeyDown, this);
14509 this.enabled = true;
14514 * Disable this KeyMap
14516 disable: function(){
14518 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14519 this.enabled = false;
14524 * Ext JS Library 1.1.1
14525 * Copyright(c) 2006-2007, Ext JS, LLC.
14527 * Originally Released Under LGPL - original licence link has changed is not relivant.
14530 * <script type="text/javascript">
14535 * @class Roo.util.TextMetrics
14536 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14537 * wide, in pixels, a given block of text will be.
14540 Roo.util.TextMetrics = function(){
14544 * Measures the size of the specified text
14545 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14546 * that can affect the size of the rendered text
14547 * @param {String} text The text to measure
14548 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14549 * in order to accurately measure the text height
14550 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14552 measure : function(el, text, fixedWidth){
14554 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14557 shared.setFixedWidth(fixedWidth || 'auto');
14558 return shared.getSize(text);
14562 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14563 * the overhead of multiple calls to initialize the style properties on each measurement.
14564 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14565 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14566 * in order to accurately measure the text height
14567 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14569 createInstance : function(el, fixedWidth){
14570 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14577 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14578 var ml = new Roo.Element(document.createElement('div'));
14579 document.body.appendChild(ml.dom);
14580 ml.position('absolute');
14581 ml.setLeftTop(-1000, -1000);
14585 ml.setWidth(fixedWidth);
14590 * Returns the size of the specified text based on the internal element's style and width properties
14591 * @memberOf Roo.util.TextMetrics.Instance#
14592 * @param {String} text The text to measure
14593 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14595 getSize : function(text){
14597 var s = ml.getSize();
14603 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14604 * that can affect the size of the rendered text
14605 * @memberOf Roo.util.TextMetrics.Instance#
14606 * @param {String/HTMLElement} el The element, dom node or id
14608 bind : function(el){
14610 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14615 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14616 * to set a fixed width in order to accurately measure the text height.
14617 * @memberOf Roo.util.TextMetrics.Instance#
14618 * @param {Number} width The width to set on the element
14620 setFixedWidth : function(width){
14621 ml.setWidth(width);
14625 * Returns the measured width of the specified text
14626 * @memberOf Roo.util.TextMetrics.Instance#
14627 * @param {String} text The text to measure
14628 * @return {Number} width The width in pixels
14630 getWidth : function(text){
14631 ml.dom.style.width = 'auto';
14632 return this.getSize(text).width;
14636 * Returns the measured height of the specified text. For multiline text, be sure to call
14637 * {@link #setFixedWidth} if necessary.
14638 * @memberOf Roo.util.TextMetrics.Instance#
14639 * @param {String} text The text to measure
14640 * @return {Number} height The height in pixels
14642 getHeight : function(text){
14643 return this.getSize(text).height;
14647 instance.bind(bindTo);
14652 // backwards compat
14653 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14655 * Ext JS Library 1.1.1
14656 * Copyright(c) 2006-2007, Ext JS, LLC.
14658 * Originally Released Under LGPL - original licence link has changed is not relivant.
14661 * <script type="text/javascript">
14665 * @class Roo.state.Provider
14666 * Abstract base class for state provider implementations. This class provides methods
14667 * for encoding and decoding <b>typed</b> variables including dates and defines the
14668 * Provider interface.
14670 Roo.state.Provider = function(){
14672 * @event statechange
14673 * Fires when a state change occurs.
14674 * @param {Provider} this This state provider
14675 * @param {String} key The state key which was changed
14676 * @param {String} value The encoded value for the state
14679 "statechange": true
14682 Roo.state.Provider.superclass.constructor.call(this);
14684 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14686 * Returns the current value for a key
14687 * @param {String} name The key name
14688 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14689 * @return {Mixed} The state data
14691 get : function(name, defaultValue){
14692 return typeof this.state[name] == "undefined" ?
14693 defaultValue : this.state[name];
14697 * Clears a value from the state
14698 * @param {String} name The key name
14700 clear : function(name){
14701 delete this.state[name];
14702 this.fireEvent("statechange", this, name, null);
14706 * Sets the value for a key
14707 * @param {String} name The key name
14708 * @param {Mixed} value The value to set
14710 set : function(name, value){
14711 this.state[name] = value;
14712 this.fireEvent("statechange", this, name, value);
14716 * Decodes a string previously encoded with {@link #encodeValue}.
14717 * @param {String} value The value to decode
14718 * @return {Mixed} The decoded value
14720 decodeValue : function(cookie){
14721 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14722 var matches = re.exec(unescape(cookie));
14723 if(!matches || !matches[1]) return; // non state cookie
14724 var type = matches[1];
14725 var v = matches[2];
14728 return parseFloat(v);
14730 return new Date(Date.parse(v));
14735 var values = v.split("^");
14736 for(var i = 0, len = values.length; i < len; i++){
14737 all.push(this.decodeValue(values[i]));
14742 var values = v.split("^");
14743 for(var i = 0, len = values.length; i < len; i++){
14744 var kv = values[i].split("=");
14745 all[kv[0]] = this.decodeValue(kv[1]);
14754 * Encodes a value including type information. Decode with {@link #decodeValue}.
14755 * @param {Mixed} value The value to encode
14756 * @return {String} The encoded value
14758 encodeValue : function(v){
14760 if(typeof v == "number"){
14762 }else if(typeof v == "boolean"){
14763 enc = "b:" + (v ? "1" : "0");
14764 }else if(v instanceof Date){
14765 enc = "d:" + v.toGMTString();
14766 }else if(v instanceof Array){
14768 for(var i = 0, len = v.length; i < len; i++){
14769 flat += this.encodeValue(v[i]);
14770 if(i != len-1) flat += "^";
14773 }else if(typeof v == "object"){
14776 if(typeof v[key] != "function"){
14777 flat += key + "=" + this.encodeValue(v[key]) + "^";
14780 enc = "o:" + flat.substring(0, flat.length-1);
14784 return escape(enc);
14790 * Ext JS Library 1.1.1
14791 * Copyright(c) 2006-2007, Ext JS, LLC.
14793 * Originally Released Under LGPL - original licence link has changed is not relivant.
14796 * <script type="text/javascript">
14799 * @class Roo.state.Manager
14800 * This is the global state manager. By default all components that are "state aware" check this class
14801 * for state information if you don't pass them a custom state provider. In order for this class
14802 * to be useful, it must be initialized with a provider when your application initializes.
14804 // in your initialization function
14806 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14808 // supposed you have a {@link Roo.BorderLayout}
14809 var layout = new Roo.BorderLayout(...);
14810 layout.restoreState();
14811 // or a {Roo.BasicDialog}
14812 var dialog = new Roo.BasicDialog(...);
14813 dialog.restoreState();
14817 Roo.state.Manager = function(){
14818 var provider = new Roo.state.Provider();
14822 * Configures the default state provider for your application
14823 * @param {Provider} stateProvider The state provider to set
14825 setProvider : function(stateProvider){
14826 provider = stateProvider;
14830 * Returns the current value for a key
14831 * @param {String} name The key name
14832 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14833 * @return {Mixed} The state data
14835 get : function(key, defaultValue){
14836 return provider.get(key, defaultValue);
14840 * Sets the value for a key
14841 * @param {String} name The key name
14842 * @param {Mixed} value The state data
14844 set : function(key, value){
14845 provider.set(key, value);
14849 * Clears a value from the state
14850 * @param {String} name The key name
14852 clear : function(key){
14853 provider.clear(key);
14857 * Gets the currently configured state provider
14858 * @return {Provider} The state provider
14860 getProvider : function(){
14867 * Ext JS Library 1.1.1
14868 * Copyright(c) 2006-2007, Ext JS, LLC.
14870 * Originally Released Under LGPL - original licence link has changed is not relivant.
14873 * <script type="text/javascript">
14876 * @class Roo.state.CookieProvider
14877 * @extends Roo.state.Provider
14878 * The default Provider implementation which saves state via cookies.
14881 var cp = new Roo.state.CookieProvider({
14883 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14884 domain: "roojs.com"
14886 Roo.state.Manager.setProvider(cp);
14888 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14889 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14890 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14891 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14892 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14893 * domain the page is running on including the 'www' like 'www.roojs.com')
14894 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14896 * Create a new CookieProvider
14897 * @param {Object} config The configuration object
14899 Roo.state.CookieProvider = function(config){
14900 Roo.state.CookieProvider.superclass.constructor.call(this);
14902 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14903 this.domain = null;
14904 this.secure = false;
14905 Roo.apply(this, config);
14906 this.state = this.readCookies();
14909 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14911 set : function(name, value){
14912 if(typeof value == "undefined" || value === null){
14916 this.setCookie(name, value);
14917 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14921 clear : function(name){
14922 this.clearCookie(name);
14923 Roo.state.CookieProvider.superclass.clear.call(this, name);
14927 readCookies : function(){
14929 var c = document.cookie + ";";
14930 var re = /\s?(.*?)=(.*?);/g;
14932 while((matches = re.exec(c)) != null){
14933 var name = matches[1];
14934 var value = matches[2];
14935 if(name && name.substring(0,3) == "ys-"){
14936 cookies[name.substr(3)] = this.decodeValue(value);
14943 setCookie : function(name, value){
14944 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14945 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14946 ((this.path == null) ? "" : ("; path=" + this.path)) +
14947 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14948 ((this.secure == true) ? "; secure" : "");
14952 clearCookie : function(name){
14953 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14954 ((this.path == null) ? "" : ("; path=" + this.path)) +
14955 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14956 ((this.secure == true) ? "; secure" : "");
14960 * Ext JS Library 1.1.1
14961 * Copyright(c) 2006-2007, Ext JS, LLC.
14963 * Originally Released Under LGPL - original licence link has changed is not relivant.
14966 * <script type="text/javascript">
14971 * @class Roo.ComponentMgr
14972 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14975 Roo.ComponentMgr = function(){
14976 var all = new Roo.util.MixedCollection();
14980 * Registers a component.
14981 * @param {Roo.Component} c The component
14983 register : function(c){
14988 * Unregisters a component.
14989 * @param {Roo.Component} c The component
14991 unregister : function(c){
14996 * Returns a component by id
14997 * @param {String} id The component id
14999 get : function(id){
15000 return all.get(id);
15004 * Registers a function that will be called when a specified component is added to ComponentMgr
15005 * @param {String} id The component id
15006 * @param {Funtction} fn The callback function
15007 * @param {Object} scope The scope of the callback
15009 onAvailable : function(id, fn, scope){
15010 all.on("add", function(index, o){
15012 fn.call(scope || o, o);
15013 all.un("add", fn, scope);
15020 * Ext JS Library 1.1.1
15021 * Copyright(c) 2006-2007, Ext JS, LLC.
15023 * Originally Released Under LGPL - original licence link has changed is not relivant.
15026 * <script type="text/javascript">
15030 * @class Roo.Component
15031 * @extends Roo.util.Observable
15032 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15033 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15034 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15035 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15036 * All visual components (widgets) that require rendering into a layout should subclass Component.
15038 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15039 * 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
15040 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15042 Roo.Component = function(config){
15043 config = config || {};
15044 if(config.tagName || config.dom || typeof config == "string"){ // element object
15045 config = {el: config, id: config.id || config};
15047 this.initialConfig = config;
15049 Roo.apply(this, config);
15053 * Fires after the component is disabled.
15054 * @param {Roo.Component} this
15059 * Fires after the component is enabled.
15060 * @param {Roo.Component} this
15064 * @event beforeshow
15065 * Fires before the component is shown. Return false to stop the show.
15066 * @param {Roo.Component} this
15071 * Fires after the component is shown.
15072 * @param {Roo.Component} this
15076 * @event beforehide
15077 * Fires before the component is hidden. Return false to stop the hide.
15078 * @param {Roo.Component} this
15083 * Fires after the component is hidden.
15084 * @param {Roo.Component} this
15088 * @event beforerender
15089 * Fires before the component is rendered. Return false to stop the render.
15090 * @param {Roo.Component} this
15092 beforerender : true,
15095 * Fires after the component is rendered.
15096 * @param {Roo.Component} this
15100 * @event beforedestroy
15101 * Fires before the component is destroyed. Return false to stop the destroy.
15102 * @param {Roo.Component} this
15104 beforedestroy : true,
15107 * Fires after the component is destroyed.
15108 * @param {Roo.Component} this
15113 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15115 Roo.ComponentMgr.register(this);
15116 Roo.Component.superclass.constructor.call(this);
15117 this.initComponent();
15118 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15119 this.render(this.renderTo);
15120 delete this.renderTo;
15125 Roo.Component.AUTO_ID = 1000;
15127 Roo.extend(Roo.Component, Roo.util.Observable, {
15129 * @scope Roo.Component.prototype
15131 * true if this component is hidden. Read-only.
15136 * true if this component is disabled. Read-only.
15141 * true if this component has been rendered. Read-only.
15145 /** @cfg {String} disableClass
15146 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15148 disabledClass : "x-item-disabled",
15149 /** @cfg {Boolean} allowDomMove
15150 * Whether the component can move the Dom node when rendering (defaults to true).
15152 allowDomMove : true,
15153 /** @cfg {String} hideMode
15154 * How this component should hidden. Supported values are
15155 * "visibility" (css visibility), "offsets" (negative offset position) and
15156 * "display" (css display) - defaults to "display".
15158 hideMode: 'display',
15161 ctype : "Roo.Component",
15164 * @cfg {String} actionMode
15165 * which property holds the element that used for hide() / show() / disable() / enable()
15171 getActionEl : function(){
15172 return this[this.actionMode];
15175 initComponent : Roo.emptyFn,
15177 * If this is a lazy rendering component, render it to its container element.
15178 * @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.
15180 render : function(container, position){
15181 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15182 if(!container && this.el){
15183 this.el = Roo.get(this.el);
15184 container = this.el.dom.parentNode;
15185 this.allowDomMove = false;
15187 this.container = Roo.get(container);
15188 this.rendered = true;
15189 if(position !== undefined){
15190 if(typeof position == 'number'){
15191 position = this.container.dom.childNodes[position];
15193 position = Roo.getDom(position);
15196 this.onRender(this.container, position || null);
15198 this.el.addClass(this.cls);
15202 this.el.applyStyles(this.style);
15205 this.fireEvent("render", this);
15206 this.afterRender(this.container);
15218 // default function is not really useful
15219 onRender : function(ct, position){
15221 this.el = Roo.get(this.el);
15222 if(this.allowDomMove !== false){
15223 ct.dom.insertBefore(this.el.dom, position);
15229 getAutoCreate : function(){
15230 var cfg = typeof this.autoCreate == "object" ?
15231 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15232 if(this.id && !cfg.id){
15239 afterRender : Roo.emptyFn,
15242 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15243 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15245 destroy : function(){
15246 if(this.fireEvent("beforedestroy", this) !== false){
15247 this.purgeListeners();
15248 this.beforeDestroy();
15250 this.el.removeAllListeners();
15252 if(this.actionMode == "container"){
15253 this.container.remove();
15257 Roo.ComponentMgr.unregister(this);
15258 this.fireEvent("destroy", this);
15263 beforeDestroy : function(){
15268 onDestroy : function(){
15273 * Returns the underlying {@link Roo.Element}.
15274 * @return {Roo.Element} The element
15276 getEl : function(){
15281 * Returns the id of this component.
15284 getId : function(){
15289 * Try to focus this component.
15290 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15291 * @return {Roo.Component} this
15293 focus : function(selectText){
15296 if(selectText === true){
15297 this.el.dom.select();
15312 * Disable this component.
15313 * @return {Roo.Component} this
15315 disable : function(){
15319 this.disabled = true;
15320 this.fireEvent("disable", this);
15325 onDisable : function(){
15326 this.getActionEl().addClass(this.disabledClass);
15327 this.el.dom.disabled = true;
15331 * Enable this component.
15332 * @return {Roo.Component} this
15334 enable : function(){
15338 this.disabled = false;
15339 this.fireEvent("enable", this);
15344 onEnable : function(){
15345 this.getActionEl().removeClass(this.disabledClass);
15346 this.el.dom.disabled = false;
15350 * Convenience function for setting disabled/enabled by boolean.
15351 * @param {Boolean} disabled
15353 setDisabled : function(disabled){
15354 this[disabled ? "disable" : "enable"]();
15358 * Show this component.
15359 * @return {Roo.Component} this
15362 if(this.fireEvent("beforeshow", this) !== false){
15363 this.hidden = false;
15367 this.fireEvent("show", this);
15373 onShow : function(){
15374 var ae = this.getActionEl();
15375 if(this.hideMode == 'visibility'){
15376 ae.dom.style.visibility = "visible";
15377 }else if(this.hideMode == 'offsets'){
15378 ae.removeClass('x-hidden');
15380 ae.dom.style.display = "";
15385 * Hide this component.
15386 * @return {Roo.Component} this
15389 if(this.fireEvent("beforehide", this) !== false){
15390 this.hidden = true;
15394 this.fireEvent("hide", this);
15400 onHide : function(){
15401 var ae = this.getActionEl();
15402 if(this.hideMode == 'visibility'){
15403 ae.dom.style.visibility = "hidden";
15404 }else if(this.hideMode == 'offsets'){
15405 ae.addClass('x-hidden');
15407 ae.dom.style.display = "none";
15412 * Convenience function to hide or show this component by boolean.
15413 * @param {Boolean} visible True to show, false to hide
15414 * @return {Roo.Component} this
15416 setVisible: function(visible){
15426 * Returns true if this component is visible.
15428 isVisible : function(){
15429 return this.getActionEl().isVisible();
15432 cloneConfig : function(overrides){
15433 overrides = overrides || {};
15434 var id = overrides.id || Roo.id();
15435 var cfg = Roo.applyIf(overrides, this.initialConfig);
15436 cfg.id = id; // prevent dup id
15437 return new this.constructor(cfg);
15441 * Ext JS Library 1.1.1
15442 * Copyright(c) 2006-2007, Ext JS, LLC.
15444 * Originally Released Under LGPL - original licence link has changed is not relivant.
15447 * <script type="text/javascript">
15451 * @class Roo.BoxComponent
15452 * @extends Roo.Component
15453 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15454 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15455 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15456 * layout containers.
15458 * @param {Roo.Element/String/Object} config The configuration options.
15460 Roo.BoxComponent = function(config){
15461 Roo.Component.call(this, config);
15465 * Fires after the component is resized.
15466 * @param {Roo.Component} this
15467 * @param {Number} adjWidth The box-adjusted width that was set
15468 * @param {Number} adjHeight The box-adjusted height that was set
15469 * @param {Number} rawWidth The width that was originally specified
15470 * @param {Number} rawHeight The height that was originally specified
15475 * Fires after the component is moved.
15476 * @param {Roo.Component} this
15477 * @param {Number} x The new x position
15478 * @param {Number} y The new y position
15484 Roo.extend(Roo.BoxComponent, Roo.Component, {
15485 // private, set in afterRender to signify that the component has been rendered
15487 // private, used to defer height settings to subclasses
15488 deferHeight: false,
15489 /** @cfg {Number} width
15490 * width (optional) size of component
15492 /** @cfg {Number} height
15493 * height (optional) size of component
15497 * Sets the width and height of the component. This method fires the resize event. This method can accept
15498 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15499 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15500 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15501 * @return {Roo.BoxComponent} this
15503 setSize : function(w, h){
15504 // support for standard size objects
15505 if(typeof w == 'object'){
15510 if(!this.boxReady){
15516 // prevent recalcs when not needed
15517 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15520 this.lastSize = {width: w, height: h};
15522 var adj = this.adjustSize(w, h);
15523 var aw = adj.width, ah = adj.height;
15524 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15525 var rz = this.getResizeEl();
15526 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15527 rz.setSize(aw, ah);
15528 }else if(!this.deferHeight && ah !== undefined){
15530 }else if(aw !== undefined){
15533 this.onResize(aw, ah, w, h);
15534 this.fireEvent('resize', this, aw, ah, w, h);
15540 * Gets the current size of the component's underlying element.
15541 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15543 getSize : function(){
15544 return this.el.getSize();
15548 * Gets the current XY position of the component's underlying element.
15549 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15550 * @return {Array} The XY position of the element (e.g., [100, 200])
15552 getPosition : function(local){
15553 if(local === true){
15554 return [this.el.getLeft(true), this.el.getTop(true)];
15556 return this.xy || this.el.getXY();
15560 * Gets the current box measurements of the component's underlying element.
15561 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15562 * @returns {Object} box An object in the format {x, y, width, height}
15564 getBox : function(local){
15565 var s = this.el.getSize();
15567 s.x = this.el.getLeft(true);
15568 s.y = this.el.getTop(true);
15570 var xy = this.xy || this.el.getXY();
15578 * Sets the current box measurements of the component's underlying element.
15579 * @param {Object} box An object in the format {x, y, width, height}
15580 * @returns {Roo.BoxComponent} this
15582 updateBox : function(box){
15583 this.setSize(box.width, box.height);
15584 this.setPagePosition(box.x, box.y);
15589 getResizeEl : function(){
15590 return this.resizeEl || this.el;
15594 getPositionEl : function(){
15595 return this.positionEl || this.el;
15599 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15600 * This method fires the move event.
15601 * @param {Number} left The new left
15602 * @param {Number} top The new top
15603 * @returns {Roo.BoxComponent} this
15605 setPosition : function(x, y){
15608 if(!this.boxReady){
15611 var adj = this.adjustPosition(x, y);
15612 var ax = adj.x, ay = adj.y;
15614 var el = this.getPositionEl();
15615 if(ax !== undefined || ay !== undefined){
15616 if(ax !== undefined && ay !== undefined){
15617 el.setLeftTop(ax, ay);
15618 }else if(ax !== undefined){
15620 }else if(ay !== undefined){
15623 this.onPosition(ax, ay);
15624 this.fireEvent('move', this, ax, ay);
15630 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15631 * This method fires the move event.
15632 * @param {Number} x The new x position
15633 * @param {Number} y The new y position
15634 * @returns {Roo.BoxComponent} this
15636 setPagePosition : function(x, y){
15639 if(!this.boxReady){
15642 if(x === undefined || y === undefined){ // cannot translate undefined points
15645 var p = this.el.translatePoints(x, y);
15646 this.setPosition(p.left, p.top);
15651 onRender : function(ct, position){
15652 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15654 this.resizeEl = Roo.get(this.resizeEl);
15656 if(this.positionEl){
15657 this.positionEl = Roo.get(this.positionEl);
15662 afterRender : function(){
15663 Roo.BoxComponent.superclass.afterRender.call(this);
15664 this.boxReady = true;
15665 this.setSize(this.width, this.height);
15666 if(this.x || this.y){
15667 this.setPosition(this.x, this.y);
15669 if(this.pageX || this.pageY){
15670 this.setPagePosition(this.pageX, this.pageY);
15675 * Force the component's size to recalculate based on the underlying element's current height and width.
15676 * @returns {Roo.BoxComponent} this
15678 syncSize : function(){
15679 delete this.lastSize;
15680 this.setSize(this.el.getWidth(), this.el.getHeight());
15685 * Called after the component is resized, this method is empty by default but can be implemented by any
15686 * subclass that needs to perform custom logic after a resize occurs.
15687 * @param {Number} adjWidth The box-adjusted width that was set
15688 * @param {Number} adjHeight The box-adjusted height that was set
15689 * @param {Number} rawWidth The width that was originally specified
15690 * @param {Number} rawHeight The height that was originally specified
15692 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15697 * Called after the component is moved, this method is empty by default but can be implemented by any
15698 * subclass that needs to perform custom logic after a move occurs.
15699 * @param {Number} x The new x position
15700 * @param {Number} y The new y position
15702 onPosition : function(x, y){
15707 adjustSize : function(w, h){
15708 if(this.autoWidth){
15711 if(this.autoHeight){
15714 return {width : w, height: h};
15718 adjustPosition : function(x, y){
15719 return {x : x, y: y};
15722 * Original code for Roojs - LGPL
15723 * <script type="text/javascript">
15727 * @class Roo.XComponent
15728 * A delayed Element creator...
15729 * Or a way to group chunks of interface together.
15731 * Mypart.xyx = new Roo.XComponent({
15733 parent : 'Mypart.xyz', // empty == document.element.!!
15737 disabled : function() {}
15739 tree : function() { // return an tree of xtype declared components
15743 xtype : 'NestedLayoutPanel',
15750 * It can be used to build a big heiracy, with parent etc.
15751 * or you can just use this to render a single compoent to a dom element
15752 * MYPART.render(Roo.Element | String(id) | dom_element )
15754 * @extends Roo.util.Observable
15756 * @param cfg {Object} configuration of component
15759 Roo.XComponent = function(cfg) {
15760 Roo.apply(this, cfg);
15764 * Fires when this the componnt is built
15765 * @param {Roo.XComponent} c the component
15770 this.region = this.region || 'center'; // default..
15771 Roo.XComponent.register(this);
15772 this.modules = false;
15773 this.el = false; // where the layout goes..
15777 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15780 * The created element (with Roo.factory())
15781 * @type {Roo.Layout}
15787 * for BC - use el in new code
15788 * @type {Roo.Layout}
15794 * for BC - use el in new code
15795 * @type {Roo.Layout}
15800 * @cfg {Function|boolean} disabled
15801 * If this module is disabled by some rule, return true from the funtion
15806 * @cfg {String} parent
15807 * Name of parent element which it get xtype added to..
15812 * @cfg {String} order
15813 * Used to set the order in which elements are created (usefull for multiple tabs)
15818 * @cfg {String} name
15819 * String to display while loading.
15823 * @cfg {String} region
15824 * Region to render component to (defaults to center)
15829 * @cfg {Array} items
15830 * A single item array - the first element is the root of the tree..
15831 * It's done this way to stay compatible with the Xtype system...
15837 * The method that retuns the tree of parts that make up this compoennt
15844 * render element to dom or tree
15845 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15848 render : function(el)
15852 var hp = this.parent ? 1 : 0;
15854 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15855 // if parent is a '#.....' string, then let's use that..
15856 var ename = this.parent.substr(1)
15857 this.parent = (this.parent == '#bootstrap') ? { el : true} : false; // flags it as a top module...
15858 el = Roo.get(ename);
15859 if (!el && !this.parent) {
15860 Roo.log("Warning - element can not be found :#" + ename );
15866 if (!this.parent) {
15868 el = el ? Roo.get(el) : false;
15870 // it's a top level one..
15872 el : new Roo.BorderLayout(el || document.body, {
15878 tabPosition: 'top',
15879 //resizeTabs: true,
15880 alwaysShowTabs: el && hp? false : true,
15881 hideTabs: el || !hp ? true : false,
15888 if (!this.parent.el) {
15889 // probably an old style ctor, which has been disabled.
15893 // The 'tree' method is '_tree now'
15895 var tree = this._tree ? this._tree() : this.tree();
15896 tree.region = tree.region || this.region;
15897 if (this.parent.el === true) {
15898 // bootstrap... - body..
15899 this.parent.el = Roo.factory(tree);
15901 this.el = this.parent.el.addxtype(tree);
15902 this.fireEvent('built', this);
15904 this.panel = this.el;
15905 this.layout = this.panel.layout;
15906 this.parentLayout = this.parent.layout || false;
15912 Roo.apply(Roo.XComponent, {
15914 * @property hideProgress
15915 * true to disable the building progress bar.. usefull on single page renders.
15918 hideProgress : false,
15920 * @property buildCompleted
15921 * True when the builder has completed building the interface.
15924 buildCompleted : false,
15927 * @property topModule
15928 * the upper most module - uses document.element as it's constructor.
15935 * @property modules
15936 * array of modules to be created by registration system.
15937 * @type {Array} of Roo.XComponent
15942 * @property elmodules
15943 * array of modules to be created by which use #ID
15944 * @type {Array} of Roo.XComponent
15951 * Register components to be built later.
15953 * This solves the following issues
15954 * - Building is not done on page load, but after an authentication process has occured.
15955 * - Interface elements are registered on page load
15956 * - Parent Interface elements may not be loaded before child, so this handles that..
15963 module : 'Pman.Tab.projectMgr',
15965 parent : 'Pman.layout',
15966 disabled : false, // or use a function..
15969 * * @param {Object} details about module
15971 register : function(obj) {
15973 Roo.XComponent.event.fireEvent('register', obj);
15974 switch(typeof(obj.disabled) ) {
15980 if ( obj.disabled() ) {
15986 if (obj.disabled) {
15992 this.modules.push(obj);
15996 * convert a string to an object..
15997 * eg. 'AAA.BBB' -> finds AAA.BBB
16001 toObject : function(str)
16003 if (!str || typeof(str) == 'object') {
16006 if (str.substring(0,1) == '#') {
16010 var ar = str.split('.');
16015 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16017 throw "Module not found : " + str;
16021 throw "Module not found : " + str;
16023 Roo.each(ar, function(e) {
16024 if (typeof(o[e]) == 'undefined') {
16025 throw "Module not found : " + str;
16036 * move modules into their correct place in the tree..
16039 preBuild : function ()
16042 Roo.each(this.modules , function (obj)
16044 Roo.XComponent.event.fireEvent('beforebuild', obj);
16046 var opar = obj.parent;
16048 obj.parent = this.toObject(opar);
16050 Roo.log("parent:toObject failed: " + e.toString());
16055 Roo.debug && Roo.log("GOT top level module");
16056 Roo.debug && Roo.log(obj);
16057 obj.modules = new Roo.util.MixedCollection(false,
16058 function(o) { return o.order + '' }
16060 this.topModule = obj;
16063 // parent is a string (usually a dom element name..)
16064 if (typeof(obj.parent) == 'string') {
16065 this.elmodules.push(obj);
16068 if (obj.parent.constructor != Roo.XComponent) {
16069 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16071 if (!obj.parent.modules) {
16072 obj.parent.modules = new Roo.util.MixedCollection(false,
16073 function(o) { return o.order + '' }
16076 if (obj.parent.disabled) {
16077 obj.disabled = true;
16079 obj.parent.modules.add(obj);
16084 * make a list of modules to build.
16085 * @return {Array} list of modules.
16088 buildOrder : function()
16091 var cmp = function(a,b) {
16092 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16094 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16095 throw "No top level modules to build";
16098 // make a flat list in order of modules to build.
16099 var mods = this.topModule ? [ this.topModule ] : [];
16102 // elmodules (is a list of DOM based modules )
16103 Roo.each(this.elmodules, function(e) {
16105 if (!this.topModule &&
16106 typeof(e.parent) == 'string' &&
16107 e.parent.substring(0,1) == '#' &&
16108 Roo.get(e.parent.substr(1))
16111 _this.topModule = e;
16117 // add modules to their parents..
16118 var addMod = function(m) {
16119 Roo.debug && Roo.log("build Order: add: " + m.name);
16122 if (m.modules && !m.disabled) {
16123 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16124 m.modules.keySort('ASC', cmp );
16125 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16127 m.modules.each(addMod);
16129 Roo.debug && Roo.log("build Order: no child modules");
16131 // not sure if this is used any more..
16133 m.finalize.name = m.name + " (clean up) ";
16134 mods.push(m.finalize);
16138 if (this.topModule && this.topModule.modules) {
16139 this.topModule.modules.keySort('ASC', cmp );
16140 this.topModule.modules.each(addMod);
16146 * Build the registered modules.
16147 * @param {Object} parent element.
16148 * @param {Function} optional method to call after module has been added.
16156 var mods = this.buildOrder();
16158 //this.allmods = mods;
16159 //Roo.debug && Roo.log(mods);
16161 if (!mods.length) { // should not happen
16162 throw "NO modules!!!";
16166 var msg = "Building Interface...";
16167 // flash it up as modal - so we store the mask!?
16168 if (!this.hideProgress && Roo.MessageBox) {
16169 Roo.MessageBox.show({ title: 'loading' });
16170 Roo.MessageBox.show({
16171 title: "Please wait...",
16180 var total = mods.length;
16183 var progressRun = function() {
16184 if (!mods.length) {
16185 Roo.debug && Roo.log('hide?');
16186 if (!this.hideProgress && Roo.MessageBox) {
16187 Roo.MessageBox.hide();
16189 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16195 var m = mods.shift();
16198 Roo.debug && Roo.log(m);
16199 // not sure if this is supported any more.. - modules that are are just function
16200 if (typeof(m) == 'function') {
16202 return progressRun.defer(10, _this);
16206 msg = "Building Interface " + (total - mods.length) +
16208 (m.name ? (' - ' + m.name) : '');
16209 Roo.debug && Roo.log(msg);
16210 if (!this.hideProgress && Roo.MessageBox) {
16211 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16215 // is the module disabled?
16216 var disabled = (typeof(m.disabled) == 'function') ?
16217 m.disabled.call(m.module.disabled) : m.disabled;
16221 return progressRun(); // we do not update the display!
16229 // it's 10 on top level, and 1 on others??? why...
16230 return progressRun.defer(10, _this);
16233 progressRun.defer(1, _this);
16247 * wrapper for event.on - aliased later..
16248 * Typically use to register a event handler for register:
16250 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16259 Roo.XComponent.event = new Roo.util.Observable({
16263 * Fires when an Component is registered,
16264 * set the disable property on the Component to stop registration.
16265 * @param {Roo.XComponent} c the component being registerd.
16270 * @event beforebuild
16271 * Fires before each Component is built
16272 * can be used to apply permissions.
16273 * @param {Roo.XComponent} c the component being registerd.
16276 'beforebuild' : true,
16278 * @event buildcomplete
16279 * Fires on the top level element when all elements have been built
16280 * @param {Roo.XComponent} the top level component.
16282 'buildcomplete' : true
16287 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16290 * Ext JS Library 1.1.1
16291 * Copyright(c) 2006-2007, Ext JS, LLC.
16293 * Originally Released Under LGPL - original licence link has changed is not relivant.
16296 * <script type="text/javascript">
16302 * These classes are derivatives of the similarly named classes in the YUI Library.
16303 * The original license:
16304 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16305 * Code licensed under the BSD License:
16306 * http://developer.yahoo.net/yui/license.txt
16311 var Event=Roo.EventManager;
16312 var Dom=Roo.lib.Dom;
16315 * @class Roo.dd.DragDrop
16316 * @extends Roo.util.Observable
16317 * Defines the interface and base operation of items that that can be
16318 * dragged or can be drop targets. It was designed to be extended, overriding
16319 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16320 * Up to three html elements can be associated with a DragDrop instance:
16322 * <li>linked element: the element that is passed into the constructor.
16323 * This is the element which defines the boundaries for interaction with
16324 * other DragDrop objects.</li>
16325 * <li>handle element(s): The drag operation only occurs if the element that
16326 * was clicked matches a handle element. By default this is the linked
16327 * element, but there are times that you will want only a portion of the
16328 * linked element to initiate the drag operation, and the setHandleElId()
16329 * method provides a way to define this.</li>
16330 * <li>drag element: this represents the element that would be moved along
16331 * with the cursor during a drag operation. By default, this is the linked
16332 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16333 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16336 * This class should not be instantiated until the onload event to ensure that
16337 * the associated elements are available.
16338 * The following would define a DragDrop obj that would interact with any
16339 * other DragDrop obj in the "group1" group:
16341 * dd = new Roo.dd.DragDrop("div1", "group1");
16343 * Since none of the event handlers have been implemented, nothing would
16344 * actually happen if you were to run the code above. Normally you would
16345 * override this class or one of the default implementations, but you can
16346 * also override the methods you want on an instance of the class...
16348 * dd.onDragDrop = function(e, id) {
16349 * alert("dd was dropped on " + id);
16353 * @param {String} id of the element that is linked to this instance
16354 * @param {String} sGroup the group of related DragDrop objects
16355 * @param {object} config an object containing configurable attributes
16356 * Valid properties for DragDrop:
16357 * padding, isTarget, maintainOffset, primaryButtonOnly
16359 Roo.dd.DragDrop = function(id, sGroup, config) {
16361 this.init(id, sGroup, config);
16366 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16369 * The id of the element associated with this object. This is what we
16370 * refer to as the "linked element" because the size and position of
16371 * this element is used to determine when the drag and drop objects have
16379 * Configuration attributes passed into the constructor
16386 * The id of the element that will be dragged. By default this is same
16387 * as the linked element , but could be changed to another element. Ex:
16389 * @property dragElId
16396 * the id of the element that initiates the drag operation. By default
16397 * this is the linked element, but could be changed to be a child of this
16398 * element. This lets us do things like only starting the drag when the
16399 * header element within the linked html element is clicked.
16400 * @property handleElId
16407 * An associative array of HTML tags that will be ignored if clicked.
16408 * @property invalidHandleTypes
16409 * @type {string: string}
16411 invalidHandleTypes: null,
16414 * An associative array of ids for elements that will be ignored if clicked
16415 * @property invalidHandleIds
16416 * @type {string: string}
16418 invalidHandleIds: null,
16421 * An indexted array of css class names for elements that will be ignored
16423 * @property invalidHandleClasses
16426 invalidHandleClasses: null,
16429 * The linked element's absolute X position at the time the drag was
16431 * @property startPageX
16438 * The linked element's absolute X position at the time the drag was
16440 * @property startPageY
16447 * The group defines a logical collection of DragDrop objects that are
16448 * related. Instances only get events when interacting with other
16449 * DragDrop object in the same group. This lets us define multiple
16450 * groups using a single DragDrop subclass if we want.
16452 * @type {string: string}
16457 * Individual drag/drop instances can be locked. This will prevent
16458 * onmousedown start drag.
16466 * Lock this instance
16469 lock: function() { this.locked = true; },
16472 * Unlock this instace
16475 unlock: function() { this.locked = false; },
16478 * By default, all insances can be a drop target. This can be disabled by
16479 * setting isTarget to false.
16486 * The padding configured for this drag and drop object for calculating
16487 * the drop zone intersection with this object.
16494 * Cached reference to the linked element
16495 * @property _domRef
16501 * Internal typeof flag
16502 * @property __ygDragDrop
16505 __ygDragDrop: true,
16508 * Set to true when horizontal contraints are applied
16509 * @property constrainX
16516 * Set to true when vertical contraints are applied
16517 * @property constrainY
16524 * The left constraint
16532 * The right constraint
16540 * The up constraint
16549 * The down constraint
16557 * Maintain offsets when we resetconstraints. Set to true when you want
16558 * the position of the element relative to its parent to stay the same
16559 * when the page changes
16561 * @property maintainOffset
16564 maintainOffset: false,
16567 * Array of pixel locations the element will snap to if we specified a
16568 * horizontal graduation/interval. This array is generated automatically
16569 * when you define a tick interval.
16576 * Array of pixel locations the element will snap to if we specified a
16577 * vertical graduation/interval. This array is generated automatically
16578 * when you define a tick interval.
16585 * By default the drag and drop instance will only respond to the primary
16586 * button click (left button for a right-handed mouse). Set to true to
16587 * allow drag and drop to start with any mouse click that is propogated
16589 * @property primaryButtonOnly
16592 primaryButtonOnly: true,
16595 * The availabe property is false until the linked dom element is accessible.
16596 * @property available
16602 * By default, drags can only be initiated if the mousedown occurs in the
16603 * region the linked element is. This is done in part to work around a
16604 * bug in some browsers that mis-report the mousedown if the previous
16605 * mouseup happened outside of the window. This property is set to true
16606 * if outer handles are defined.
16608 * @property hasOuterHandles
16612 hasOuterHandles: false,
16615 * Code that executes immediately before the startDrag event
16616 * @method b4StartDrag
16619 b4StartDrag: function(x, y) { },
16622 * Abstract method called after a drag/drop object is clicked
16623 * and the drag or mousedown time thresholds have beeen met.
16624 * @method startDrag
16625 * @param {int} X click location
16626 * @param {int} Y click location
16628 startDrag: function(x, y) { /* override this */ },
16631 * Code that executes immediately before the onDrag event
16635 b4Drag: function(e) { },
16638 * Abstract method called during the onMouseMove event while dragging an
16641 * @param {Event} e the mousemove event
16643 onDrag: function(e) { /* override this */ },
16646 * Abstract method called when this element fist begins hovering over
16647 * another DragDrop obj
16648 * @method onDragEnter
16649 * @param {Event} e the mousemove event
16650 * @param {String|DragDrop[]} id In POINT mode, the element
16651 * id this is hovering over. In INTERSECT mode, an array of one or more
16652 * dragdrop items being hovered over.
16654 onDragEnter: function(e, id) { /* override this */ },
16657 * Code that executes immediately before the onDragOver event
16658 * @method b4DragOver
16661 b4DragOver: function(e) { },
16664 * Abstract method called when this element is hovering over another
16666 * @method onDragOver
16667 * @param {Event} e the mousemove event
16668 * @param {String|DragDrop[]} id In POINT mode, the element
16669 * id this is hovering over. In INTERSECT mode, an array of dd items
16670 * being hovered over.
16672 onDragOver: function(e, id) { /* override this */ },
16675 * Code that executes immediately before the onDragOut event
16676 * @method b4DragOut
16679 b4DragOut: function(e) { },
16682 * Abstract method called when we are no longer hovering over an element
16683 * @method onDragOut
16684 * @param {Event} e the mousemove event
16685 * @param {String|DragDrop[]} id In POINT mode, the element
16686 * id this was hovering over. In INTERSECT mode, an array of dd items
16687 * that the mouse is no longer over.
16689 onDragOut: function(e, id) { /* override this */ },
16692 * Code that executes immediately before the onDragDrop event
16693 * @method b4DragDrop
16696 b4DragDrop: function(e) { },
16699 * Abstract method called when this item is dropped on another DragDrop
16701 * @method onDragDrop
16702 * @param {Event} e the mouseup event
16703 * @param {String|DragDrop[]} id In POINT mode, the element
16704 * id this was dropped on. In INTERSECT mode, an array of dd items this
16707 onDragDrop: function(e, id) { /* override this */ },
16710 * Abstract method called when this item is dropped on an area with no
16712 * @method onInvalidDrop
16713 * @param {Event} e the mouseup event
16715 onInvalidDrop: function(e) { /* override this */ },
16718 * Code that executes immediately before the endDrag event
16719 * @method b4EndDrag
16722 b4EndDrag: function(e) { },
16725 * Fired when we are done dragging the object
16727 * @param {Event} e the mouseup event
16729 endDrag: function(e) { /* override this */ },
16732 * Code executed immediately before the onMouseDown event
16733 * @method b4MouseDown
16734 * @param {Event} e the mousedown event
16737 b4MouseDown: function(e) { },
16740 * Event handler that fires when a drag/drop obj gets a mousedown
16741 * @method onMouseDown
16742 * @param {Event} e the mousedown event
16744 onMouseDown: function(e) { /* override this */ },
16747 * Event handler that fires when a drag/drop obj gets a mouseup
16748 * @method onMouseUp
16749 * @param {Event} e the mouseup event
16751 onMouseUp: function(e) { /* override this */ },
16754 * Override the onAvailable method to do what is needed after the initial
16755 * position was determined.
16756 * @method onAvailable
16758 onAvailable: function () {
16762 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16765 defaultPadding : {left:0, right:0, top:0, bottom:0},
16768 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16772 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16773 { dragElId: "existingProxyDiv" });
16774 dd.startDrag = function(){
16775 this.constrainTo("parent-id");
16778 * Or you can initalize it using the {@link Roo.Element} object:
16780 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16781 startDrag : function(){
16782 this.constrainTo("parent-id");
16786 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16787 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16788 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16789 * an object containing the sides to pad. For example: {right:10, bottom:10}
16790 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16792 constrainTo : function(constrainTo, pad, inContent){
16793 if(typeof pad == "number"){
16794 pad = {left: pad, right:pad, top:pad, bottom:pad};
16796 pad = pad || this.defaultPadding;
16797 var b = Roo.get(this.getEl()).getBox();
16798 var ce = Roo.get(constrainTo);
16799 var s = ce.getScroll();
16800 var c, cd = ce.dom;
16801 if(cd == document.body){
16802 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16805 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16809 var topSpace = b.y - c.y;
16810 var leftSpace = b.x - c.x;
16812 this.resetConstraints();
16813 this.setXConstraint(leftSpace - (pad.left||0), // left
16814 c.width - leftSpace - b.width - (pad.right||0) //right
16816 this.setYConstraint(topSpace - (pad.top||0), //top
16817 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16822 * Returns a reference to the linked element
16824 * @return {HTMLElement} the html element
16826 getEl: function() {
16827 if (!this._domRef) {
16828 this._domRef = Roo.getDom(this.id);
16831 return this._domRef;
16835 * Returns a reference to the actual element to drag. By default this is
16836 * the same as the html element, but it can be assigned to another
16837 * element. An example of this can be found in Roo.dd.DDProxy
16838 * @method getDragEl
16839 * @return {HTMLElement} the html element
16841 getDragEl: function() {
16842 return Roo.getDom(this.dragElId);
16846 * Sets up the DragDrop object. Must be called in the constructor of any
16847 * Roo.dd.DragDrop subclass
16849 * @param id the id of the linked element
16850 * @param {String} sGroup the group of related items
16851 * @param {object} config configuration attributes
16853 init: function(id, sGroup, config) {
16854 this.initTarget(id, sGroup, config);
16855 if (!Roo.isTouch) {
16856 Event.on(this.id, "mousedown", this.handleMouseDown, this);
16858 Event.on(this.id, "touchstart", this.handleMouseDown, this);
16859 // Event.on(this.id, "selectstart", Event.preventDefault);
16863 * Initializes Targeting functionality only... the object does not
16864 * get a mousedown handler.
16865 * @method initTarget
16866 * @param id the id of the linked element
16867 * @param {String} sGroup the group of related items
16868 * @param {object} config configuration attributes
16870 initTarget: function(id, sGroup, config) {
16872 // configuration attributes
16873 this.config = config || {};
16875 // create a local reference to the drag and drop manager
16876 this.DDM = Roo.dd.DDM;
16877 // initialize the groups array
16880 // assume that we have an element reference instead of an id if the
16881 // parameter is not a string
16882 if (typeof id !== "string") {
16889 // add to an interaction group
16890 this.addToGroup((sGroup) ? sGroup : "default");
16892 // We don't want to register this as the handle with the manager
16893 // so we just set the id rather than calling the setter.
16894 this.handleElId = id;
16896 // the linked element is the element that gets dragged by default
16897 this.setDragElId(id);
16899 // by default, clicked anchors will not start drag operations.
16900 this.invalidHandleTypes = { A: "A" };
16901 this.invalidHandleIds = {};
16902 this.invalidHandleClasses = [];
16904 this.applyConfig();
16906 this.handleOnAvailable();
16910 * Applies the configuration parameters that were passed into the constructor.
16911 * This is supposed to happen at each level through the inheritance chain. So
16912 * a DDProxy implentation will execute apply config on DDProxy, DD, and
16913 * DragDrop in order to get all of the parameters that are available in
16915 * @method applyConfig
16917 applyConfig: function() {
16919 // configurable properties:
16920 // padding, isTarget, maintainOffset, primaryButtonOnly
16921 this.padding = this.config.padding || [0, 0, 0, 0];
16922 this.isTarget = (this.config.isTarget !== false);
16923 this.maintainOffset = (this.config.maintainOffset);
16924 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
16929 * Executed when the linked element is available
16930 * @method handleOnAvailable
16933 handleOnAvailable: function() {
16934 this.available = true;
16935 this.resetConstraints();
16936 this.onAvailable();
16940 * Configures the padding for the target zone in px. Effectively expands
16941 * (or reduces) the virtual object size for targeting calculations.
16942 * Supports css-style shorthand; if only one parameter is passed, all sides
16943 * will have that padding, and if only two are passed, the top and bottom
16944 * will have the first param, the left and right the second.
16945 * @method setPadding
16946 * @param {int} iTop Top pad
16947 * @param {int} iRight Right pad
16948 * @param {int} iBot Bot pad
16949 * @param {int} iLeft Left pad
16951 setPadding: function(iTop, iRight, iBot, iLeft) {
16952 // this.padding = [iLeft, iRight, iTop, iBot];
16953 if (!iRight && 0 !== iRight) {
16954 this.padding = [iTop, iTop, iTop, iTop];
16955 } else if (!iBot && 0 !== iBot) {
16956 this.padding = [iTop, iRight, iTop, iRight];
16958 this.padding = [iTop, iRight, iBot, iLeft];
16963 * Stores the initial placement of the linked element.
16964 * @method setInitialPosition
16965 * @param {int} diffX the X offset, default 0
16966 * @param {int} diffY the Y offset, default 0
16968 setInitPosition: function(diffX, diffY) {
16969 var el = this.getEl();
16971 if (!this.DDM.verifyEl(el)) {
16975 var dx = diffX || 0;
16976 var dy = diffY || 0;
16978 var p = Dom.getXY( el );
16980 this.initPageX = p[0] - dx;
16981 this.initPageY = p[1] - dy;
16983 this.lastPageX = p[0];
16984 this.lastPageY = p[1];
16987 this.setStartPosition(p);
16991 * Sets the start position of the element. This is set when the obj
16992 * is initialized, the reset when a drag is started.
16993 * @method setStartPosition
16994 * @param pos current position (from previous lookup)
16997 setStartPosition: function(pos) {
16998 var p = pos || Dom.getXY( this.getEl() );
16999 this.deltaSetXY = null;
17001 this.startPageX = p[0];
17002 this.startPageY = p[1];
17006 * Add this instance to a group of related drag/drop objects. All
17007 * instances belong to at least one group, and can belong to as many
17008 * groups as needed.
17009 * @method addToGroup
17010 * @param sGroup {string} the name of the group
17012 addToGroup: function(sGroup) {
17013 this.groups[sGroup] = true;
17014 this.DDM.regDragDrop(this, sGroup);
17018 * Remove's this instance from the supplied interaction group
17019 * @method removeFromGroup
17020 * @param {string} sGroup The group to drop
17022 removeFromGroup: function(sGroup) {
17023 if (this.groups[sGroup]) {
17024 delete this.groups[sGroup];
17027 this.DDM.removeDDFromGroup(this, sGroup);
17031 * Allows you to specify that an element other than the linked element
17032 * will be moved with the cursor during a drag
17033 * @method setDragElId
17034 * @param id {string} the id of the element that will be used to initiate the drag
17036 setDragElId: function(id) {
17037 this.dragElId = id;
17041 * Allows you to specify a child of the linked element that should be
17042 * used to initiate the drag operation. An example of this would be if
17043 * you have a content div with text and links. Clicking anywhere in the
17044 * content area would normally start the drag operation. Use this method
17045 * to specify that an element inside of the content div is the element
17046 * that starts the drag operation.
17047 * @method setHandleElId
17048 * @param id {string} the id of the element that will be used to
17049 * initiate the drag.
17051 setHandleElId: function(id) {
17052 if (typeof id !== "string") {
17055 this.handleElId = id;
17056 this.DDM.regHandle(this.id, id);
17060 * Allows you to set an element outside of the linked element as a drag
17062 * @method setOuterHandleElId
17063 * @param id the id of the element that will be used to initiate the drag
17065 setOuterHandleElId: function(id) {
17066 if (typeof id !== "string") {
17069 Event.on(id, "mousedown",
17070 this.handleMouseDown, this);
17071 this.setHandleElId(id);
17073 this.hasOuterHandles = true;
17077 * Remove all drag and drop hooks for this element
17080 unreg: function() {
17081 Event.un(this.id, "mousedown",
17082 this.handleMouseDown);
17083 Event.un(this.id, "touchstart",
17084 this.handleMouseDown);
17085 this._domRef = null;
17086 this.DDM._remove(this);
17089 destroy : function(){
17094 * Returns true if this instance is locked, or the drag drop mgr is locked
17095 * (meaning that all drag/drop is disabled on the page.)
17097 * @return {boolean} true if this obj or all drag/drop is locked, else
17100 isLocked: function() {
17101 return (this.DDM.isLocked() || this.locked);
17105 * Fired when this object is clicked
17106 * @method handleMouseDown
17108 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17111 handleMouseDown: function(e, oDD){
17113 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17114 //Roo.log('not touch/ button !=0');
17117 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17118 return; // double touch..
17122 if (this.isLocked()) {
17123 //Roo.log('locked');
17127 this.DDM.refreshCache(this.groups);
17128 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17129 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17130 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17131 //Roo.log('no outer handes or not over target');
17134 // Roo.log('check validator');
17135 if (this.clickValidator(e)) {
17136 // Roo.log('validate success');
17137 // set the initial element position
17138 this.setStartPosition();
17141 this.b4MouseDown(e);
17142 this.onMouseDown(e);
17144 this.DDM.handleMouseDown(e, this);
17146 this.DDM.stopEvent(e);
17154 clickValidator: function(e) {
17155 var target = e.getTarget();
17156 return ( this.isValidHandleChild(target) &&
17157 (this.id == this.handleElId ||
17158 this.DDM.handleWasClicked(target, this.id)) );
17162 * Allows you to specify a tag name that should not start a drag operation
17163 * when clicked. This is designed to facilitate embedding links within a
17164 * drag handle that do something other than start the drag.
17165 * @method addInvalidHandleType
17166 * @param {string} tagName the type of element to exclude
17168 addInvalidHandleType: function(tagName) {
17169 var type = tagName.toUpperCase();
17170 this.invalidHandleTypes[type] = type;
17174 * Lets you to specify an element id for a child of a drag handle
17175 * that should not initiate a drag
17176 * @method addInvalidHandleId
17177 * @param {string} id the element id of the element you wish to ignore
17179 addInvalidHandleId: function(id) {
17180 if (typeof id !== "string") {
17183 this.invalidHandleIds[id] = id;
17187 * Lets you specify a css class of elements that will not initiate a drag
17188 * @method addInvalidHandleClass
17189 * @param {string} cssClass the class of the elements you wish to ignore
17191 addInvalidHandleClass: function(cssClass) {
17192 this.invalidHandleClasses.push(cssClass);
17196 * Unsets an excluded tag name set by addInvalidHandleType
17197 * @method removeInvalidHandleType
17198 * @param {string} tagName the type of element to unexclude
17200 removeInvalidHandleType: function(tagName) {
17201 var type = tagName.toUpperCase();
17202 // this.invalidHandleTypes[type] = null;
17203 delete this.invalidHandleTypes[type];
17207 * Unsets an invalid handle id
17208 * @method removeInvalidHandleId
17209 * @param {string} id the id of the element to re-enable
17211 removeInvalidHandleId: function(id) {
17212 if (typeof id !== "string") {
17215 delete this.invalidHandleIds[id];
17219 * Unsets an invalid css class
17220 * @method removeInvalidHandleClass
17221 * @param {string} cssClass the class of the element(s) you wish to
17224 removeInvalidHandleClass: function(cssClass) {
17225 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17226 if (this.invalidHandleClasses[i] == cssClass) {
17227 delete this.invalidHandleClasses[i];
17233 * Checks the tag exclusion list to see if this click should be ignored
17234 * @method isValidHandleChild
17235 * @param {HTMLElement} node the HTMLElement to evaluate
17236 * @return {boolean} true if this is a valid tag type, false if not
17238 isValidHandleChild: function(node) {
17241 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17244 nodeName = node.nodeName.toUpperCase();
17246 nodeName = node.nodeName;
17248 valid = valid && !this.invalidHandleTypes[nodeName];
17249 valid = valid && !this.invalidHandleIds[node.id];
17251 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17252 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17261 * Create the array of horizontal tick marks if an interval was specified
17262 * in setXConstraint().
17263 * @method setXTicks
17266 setXTicks: function(iStartX, iTickSize) {
17268 this.xTickSize = iTickSize;
17272 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17274 this.xTicks[this.xTicks.length] = i;
17279 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17281 this.xTicks[this.xTicks.length] = i;
17286 this.xTicks.sort(this.DDM.numericSort) ;
17290 * Create the array of vertical tick marks if an interval was specified in
17291 * setYConstraint().
17292 * @method setYTicks
17295 setYTicks: function(iStartY, iTickSize) {
17297 this.yTickSize = iTickSize;
17301 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17303 this.yTicks[this.yTicks.length] = i;
17308 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17310 this.yTicks[this.yTicks.length] = i;
17315 this.yTicks.sort(this.DDM.numericSort) ;
17319 * By default, the element can be dragged any place on the screen. Use
17320 * this method to limit the horizontal travel of the element. Pass in
17321 * 0,0 for the parameters if you want to lock the drag to the y axis.
17322 * @method setXConstraint
17323 * @param {int} iLeft the number of pixels the element can move to the left
17324 * @param {int} iRight the number of pixels the element can move to the
17326 * @param {int} iTickSize optional parameter for specifying that the
17328 * should move iTickSize pixels at a time.
17330 setXConstraint: function(iLeft, iRight, iTickSize) {
17331 this.leftConstraint = iLeft;
17332 this.rightConstraint = iRight;
17334 this.minX = this.initPageX - iLeft;
17335 this.maxX = this.initPageX + iRight;
17336 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17338 this.constrainX = true;
17342 * Clears any constraints applied to this instance. Also clears ticks
17343 * since they can't exist independent of a constraint at this time.
17344 * @method clearConstraints
17346 clearConstraints: function() {
17347 this.constrainX = false;
17348 this.constrainY = false;
17353 * Clears any tick interval defined for this instance
17354 * @method clearTicks
17356 clearTicks: function() {
17357 this.xTicks = null;
17358 this.yTicks = null;
17359 this.xTickSize = 0;
17360 this.yTickSize = 0;
17364 * By default, the element can be dragged any place on the screen. Set
17365 * this to limit the vertical travel of the element. Pass in 0,0 for the
17366 * parameters if you want to lock the drag to the x axis.
17367 * @method setYConstraint
17368 * @param {int} iUp the number of pixels the element can move up
17369 * @param {int} iDown the number of pixels the element can move down
17370 * @param {int} iTickSize optional parameter for specifying that the
17371 * element should move iTickSize pixels at a time.
17373 setYConstraint: function(iUp, iDown, iTickSize) {
17374 this.topConstraint = iUp;
17375 this.bottomConstraint = iDown;
17377 this.minY = this.initPageY - iUp;
17378 this.maxY = this.initPageY + iDown;
17379 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17381 this.constrainY = true;
17386 * resetConstraints must be called if you manually reposition a dd element.
17387 * @method resetConstraints
17388 * @param {boolean} maintainOffset
17390 resetConstraints: function() {
17393 // Maintain offsets if necessary
17394 if (this.initPageX || this.initPageX === 0) {
17395 // figure out how much this thing has moved
17396 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17397 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17399 this.setInitPosition(dx, dy);
17401 // This is the first time we have detected the element's position
17403 this.setInitPosition();
17406 if (this.constrainX) {
17407 this.setXConstraint( this.leftConstraint,
17408 this.rightConstraint,
17412 if (this.constrainY) {
17413 this.setYConstraint( this.topConstraint,
17414 this.bottomConstraint,
17420 * Normally the drag element is moved pixel by pixel, but we can specify
17421 * that it move a number of pixels at a time. This method resolves the
17422 * location when we have it set up like this.
17424 * @param {int} val where we want to place the object
17425 * @param {int[]} tickArray sorted array of valid points
17426 * @return {int} the closest tick
17429 getTick: function(val, tickArray) {
17432 // If tick interval is not defined, it is effectively 1 pixel,
17433 // so we return the value passed to us.
17435 } else if (tickArray[0] >= val) {
17436 // The value is lower than the first tick, so we return the first
17438 return tickArray[0];
17440 for (var i=0, len=tickArray.length; i<len; ++i) {
17442 if (tickArray[next] && tickArray[next] >= val) {
17443 var diff1 = val - tickArray[i];
17444 var diff2 = tickArray[next] - val;
17445 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17449 // The value is larger than the last tick, so we return the last
17451 return tickArray[tickArray.length - 1];
17458 * @return {string} string representation of the dd obj
17460 toString: function() {
17461 return ("DragDrop " + this.id);
17469 * Ext JS Library 1.1.1
17470 * Copyright(c) 2006-2007, Ext JS, LLC.
17472 * Originally Released Under LGPL - original licence link has changed is not relivant.
17475 * <script type="text/javascript">
17480 * The drag and drop utility provides a framework for building drag and drop
17481 * applications. In addition to enabling drag and drop for specific elements,
17482 * the drag and drop elements are tracked by the manager class, and the
17483 * interactions between the various elements are tracked during the drag and
17484 * the implementing code is notified about these important moments.
17487 // Only load the library once. Rewriting the manager class would orphan
17488 // existing drag and drop instances.
17489 if (!Roo.dd.DragDropMgr) {
17492 * @class Roo.dd.DragDropMgr
17493 * DragDropMgr is a singleton that tracks the element interaction for
17494 * all DragDrop items in the window. Generally, you will not call
17495 * this class directly, but it does have helper methods that could
17496 * be useful in your DragDrop implementations.
17499 Roo.dd.DragDropMgr = function() {
17501 var Event = Roo.EventManager;
17506 * Two dimensional Array of registered DragDrop objects. The first
17507 * dimension is the DragDrop item group, the second the DragDrop
17510 * @type {string: string}
17517 * Array of element ids defined as drag handles. Used to determine
17518 * if the element that generated the mousedown event is actually the
17519 * handle and not the html element itself.
17520 * @property handleIds
17521 * @type {string: string}
17528 * the DragDrop object that is currently being dragged
17529 * @property dragCurrent
17537 * the DragDrop object(s) that are being hovered over
17538 * @property dragOvers
17546 * the X distance between the cursor and the object being dragged
17555 * the Y distance between the cursor and the object being dragged
17564 * Flag to determine if we should prevent the default behavior of the
17565 * events we define. By default this is true, but this can be set to
17566 * false if you need the default behavior (not recommended)
17567 * @property preventDefault
17571 preventDefault: true,
17574 * Flag to determine if we should stop the propagation of the events
17575 * we generate. This is true by default but you may want to set it to
17576 * false if the html element contains other features that require the
17578 * @property stopPropagation
17582 stopPropagation: true,
17585 * Internal flag that is set to true when drag and drop has been
17587 * @property initialized
17594 * All drag and drop can be disabled.
17602 * Called the first time an element is registered.
17608 this.initialized = true;
17612 * In point mode, drag and drop interaction is defined by the
17613 * location of the cursor during the drag/drop
17621 * In intersect mode, drag and drop interactio nis defined by the
17622 * overlap of two or more drag and drop objects.
17623 * @property INTERSECT
17630 * The current drag and drop mode. Default: POINT
17638 * Runs method on all drag and drop objects
17639 * @method _execOnAll
17643 _execOnAll: function(sMethod, args) {
17644 for (var i in this.ids) {
17645 for (var j in this.ids[i]) {
17646 var oDD = this.ids[i][j];
17647 if (! this.isTypeOfDD(oDD)) {
17650 oDD[sMethod].apply(oDD, args);
17656 * Drag and drop initialization. Sets up the global event handlers
17661 _onLoad: function() {
17665 if (!Roo.isTouch) {
17666 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17667 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17669 Event.on(document, "touchend", this.handleMouseUp, this, true);
17670 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17672 Event.on(window, "unload", this._onUnload, this, true);
17673 Event.on(window, "resize", this._onResize, this, true);
17674 // Event.on(window, "mouseout", this._test);
17679 * Reset constraints on all drag and drop objs
17680 * @method _onResize
17684 _onResize: function(e) {
17685 this._execOnAll("resetConstraints", []);
17689 * Lock all drag and drop functionality
17693 lock: function() { this.locked = true; },
17696 * Unlock all drag and drop functionality
17700 unlock: function() { this.locked = false; },
17703 * Is drag and drop locked?
17705 * @return {boolean} True if drag and drop is locked, false otherwise.
17708 isLocked: function() { return this.locked; },
17711 * Location cache that is set for all drag drop objects when a drag is
17712 * initiated, cleared when the drag is finished.
17713 * @property locationCache
17720 * Set useCache to false if you want to force object the lookup of each
17721 * drag and drop linked element constantly during a drag.
17722 * @property useCache
17729 * The number of pixels that the mouse needs to move after the
17730 * mousedown before the drag is initiated. Default=3;
17731 * @property clickPixelThresh
17735 clickPixelThresh: 3,
17738 * The number of milliseconds after the mousedown event to initiate the
17739 * drag if we don't get a mouseup event. Default=1000
17740 * @property clickTimeThresh
17744 clickTimeThresh: 350,
17747 * Flag that indicates that either the drag pixel threshold or the
17748 * mousdown time threshold has been met
17749 * @property dragThreshMet
17754 dragThreshMet: false,
17757 * Timeout used for the click time threshold
17758 * @property clickTimeout
17763 clickTimeout: null,
17766 * The X position of the mousedown event stored for later use when a
17767 * drag threshold is met.
17776 * The Y position of the mousedown event stored for later use when a
17777 * drag threshold is met.
17786 * Each DragDrop instance must be registered with the DragDropMgr.
17787 * This is executed in DragDrop.init()
17788 * @method regDragDrop
17789 * @param {DragDrop} oDD the DragDrop object to register
17790 * @param {String} sGroup the name of the group this element belongs to
17793 regDragDrop: function(oDD, sGroup) {
17794 if (!this.initialized) { this.init(); }
17796 if (!this.ids[sGroup]) {
17797 this.ids[sGroup] = {};
17799 this.ids[sGroup][oDD.id] = oDD;
17803 * Removes the supplied dd instance from the supplied group. Executed
17804 * by DragDrop.removeFromGroup, so don't call this function directly.
17805 * @method removeDDFromGroup
17809 removeDDFromGroup: function(oDD, sGroup) {
17810 if (!this.ids[sGroup]) {
17811 this.ids[sGroup] = {};
17814 var obj = this.ids[sGroup];
17815 if (obj && obj[oDD.id]) {
17816 delete obj[oDD.id];
17821 * Unregisters a drag and drop item. This is executed in
17822 * DragDrop.unreg, use that method instead of calling this directly.
17827 _remove: function(oDD) {
17828 for (var g in oDD.groups) {
17829 if (g && this.ids[g][oDD.id]) {
17830 delete this.ids[g][oDD.id];
17833 delete this.handleIds[oDD.id];
17837 * Each DragDrop handle element must be registered. This is done
17838 * automatically when executing DragDrop.setHandleElId()
17839 * @method regHandle
17840 * @param {String} sDDId the DragDrop id this element is a handle for
17841 * @param {String} sHandleId the id of the element that is the drag
17845 regHandle: function(sDDId, sHandleId) {
17846 if (!this.handleIds[sDDId]) {
17847 this.handleIds[sDDId] = {};
17849 this.handleIds[sDDId][sHandleId] = sHandleId;
17853 * Utility function to determine if a given element has been
17854 * registered as a drag drop item.
17855 * @method isDragDrop
17856 * @param {String} id the element id to check
17857 * @return {boolean} true if this element is a DragDrop item,
17861 isDragDrop: function(id) {
17862 return ( this.getDDById(id) ) ? true : false;
17866 * Returns the drag and drop instances that are in all groups the
17867 * passed in instance belongs to.
17868 * @method getRelated
17869 * @param {DragDrop} p_oDD the obj to get related data for
17870 * @param {boolean} bTargetsOnly if true, only return targetable objs
17871 * @return {DragDrop[]} the related instances
17874 getRelated: function(p_oDD, bTargetsOnly) {
17876 for (var i in p_oDD.groups) {
17877 for (j in this.ids[i]) {
17878 var dd = this.ids[i][j];
17879 if (! this.isTypeOfDD(dd)) {
17882 if (!bTargetsOnly || dd.isTarget) {
17883 oDDs[oDDs.length] = dd;
17892 * Returns true if the specified dd target is a legal target for
17893 * the specifice drag obj
17894 * @method isLegalTarget
17895 * @param {DragDrop} the drag obj
17896 * @param {DragDrop} the target
17897 * @return {boolean} true if the target is a legal target for the
17901 isLegalTarget: function (oDD, oTargetDD) {
17902 var targets = this.getRelated(oDD, true);
17903 for (var i=0, len=targets.length;i<len;++i) {
17904 if (targets[i].id == oTargetDD.id) {
17913 * My goal is to be able to transparently determine if an object is
17914 * typeof DragDrop, and the exact subclass of DragDrop. typeof
17915 * returns "object", oDD.constructor.toString() always returns
17916 * "DragDrop" and not the name of the subclass. So for now it just
17917 * evaluates a well-known variable in DragDrop.
17918 * @method isTypeOfDD
17919 * @param {Object} the object to evaluate
17920 * @return {boolean} true if typeof oDD = DragDrop
17923 isTypeOfDD: function (oDD) {
17924 return (oDD && oDD.__ygDragDrop);
17928 * Utility function to determine if a given element has been
17929 * registered as a drag drop handle for the given Drag Drop object.
17931 * @param {String} id the element id to check
17932 * @return {boolean} true if this element is a DragDrop handle, false
17936 isHandle: function(sDDId, sHandleId) {
17937 return ( this.handleIds[sDDId] &&
17938 this.handleIds[sDDId][sHandleId] );
17942 * Returns the DragDrop instance for a given id
17943 * @method getDDById
17944 * @param {String} id the id of the DragDrop object
17945 * @return {DragDrop} the drag drop object, null if it is not found
17948 getDDById: function(id) {
17949 for (var i in this.ids) {
17950 if (this.ids[i][id]) {
17951 return this.ids[i][id];
17958 * Fired after a registered DragDrop object gets the mousedown event.
17959 * Sets up the events required to track the object being dragged
17960 * @method handleMouseDown
17961 * @param {Event} e the event
17962 * @param oDD the DragDrop object being dragged
17966 handleMouseDown: function(e, oDD) {
17968 Roo.QuickTips.disable();
17970 this.currentTarget = e.getTarget();
17972 this.dragCurrent = oDD;
17974 var el = oDD.getEl();
17976 // track start position
17977 this.startX = e.getPageX();
17978 this.startY = e.getPageY();
17980 this.deltaX = this.startX - el.offsetLeft;
17981 this.deltaY = this.startY - el.offsetTop;
17983 this.dragThreshMet = false;
17985 this.clickTimeout = setTimeout(
17987 var DDM = Roo.dd.DDM;
17988 DDM.startDrag(DDM.startX, DDM.startY);
17990 this.clickTimeThresh );
17994 * Fired when either the drag pixel threshol or the mousedown hold
17995 * time threshold has been met.
17996 * @method startDrag
17997 * @param x {int} the X position of the original mousedown
17998 * @param y {int} the Y position of the original mousedown
18001 startDrag: function(x, y) {
18002 clearTimeout(this.clickTimeout);
18003 if (this.dragCurrent) {
18004 this.dragCurrent.b4StartDrag(x, y);
18005 this.dragCurrent.startDrag(x, y);
18007 this.dragThreshMet = true;
18011 * Internal function to handle the mouseup event. Will be invoked
18012 * from the context of the document.
18013 * @method handleMouseUp
18014 * @param {Event} e the event
18018 handleMouseUp: function(e) {
18021 Roo.QuickTips.enable();
18023 if (! this.dragCurrent) {
18027 clearTimeout(this.clickTimeout);
18029 if (this.dragThreshMet) {
18030 this.fireEvents(e, true);
18040 * Utility to stop event propagation and event default, if these
18041 * features are turned on.
18042 * @method stopEvent
18043 * @param {Event} e the event as returned by this.getEvent()
18046 stopEvent: function(e){
18047 if(this.stopPropagation) {
18048 e.stopPropagation();
18051 if (this.preventDefault) {
18052 e.preventDefault();
18057 * Internal function to clean up event handlers after the drag
18058 * operation is complete
18060 * @param {Event} e the event
18064 stopDrag: function(e) {
18065 // Fire the drag end event for the item that was dragged
18066 if (this.dragCurrent) {
18067 if (this.dragThreshMet) {
18068 this.dragCurrent.b4EndDrag(e);
18069 this.dragCurrent.endDrag(e);
18072 this.dragCurrent.onMouseUp(e);
18075 this.dragCurrent = null;
18076 this.dragOvers = {};
18080 * Internal function to handle the mousemove event. Will be invoked
18081 * from the context of the html element.
18083 * @TODO figure out what we can do about mouse events lost when the
18084 * user drags objects beyond the window boundary. Currently we can
18085 * detect this in internet explorer by verifying that the mouse is
18086 * down during the mousemove event. Firefox doesn't give us the
18087 * button state on the mousemove event.
18088 * @method handleMouseMove
18089 * @param {Event} e the event
18093 handleMouseMove: function(e) {
18094 if (! this.dragCurrent) {
18098 // var button = e.which || e.button;
18100 // check for IE mouseup outside of page boundary
18101 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18103 return this.handleMouseUp(e);
18106 if (!this.dragThreshMet) {
18107 var diffX = Math.abs(this.startX - e.getPageX());
18108 var diffY = Math.abs(this.startY - e.getPageY());
18109 if (diffX > this.clickPixelThresh ||
18110 diffY > this.clickPixelThresh) {
18111 this.startDrag(this.startX, this.startY);
18115 if (this.dragThreshMet) {
18116 this.dragCurrent.b4Drag(e);
18117 this.dragCurrent.onDrag(e);
18118 if(!this.dragCurrent.moveOnly){
18119 this.fireEvents(e, false);
18129 * Iterates over all of the DragDrop elements to find ones we are
18130 * hovering over or dropping on
18131 * @method fireEvents
18132 * @param {Event} e the event
18133 * @param {boolean} isDrop is this a drop op or a mouseover op?
18137 fireEvents: function(e, isDrop) {
18138 var dc = this.dragCurrent;
18140 // If the user did the mouse up outside of the window, we could
18141 // get here even though we have ended the drag.
18142 if (!dc || dc.isLocked()) {
18146 var pt = e.getPoint();
18148 // cache the previous dragOver array
18154 var enterEvts = [];
18156 // Check to see if the object(s) we were hovering over is no longer
18157 // being hovered over so we can fire the onDragOut event
18158 for (var i in this.dragOvers) {
18160 var ddo = this.dragOvers[i];
18162 if (! this.isTypeOfDD(ddo)) {
18166 if (! this.isOverTarget(pt, ddo, this.mode)) {
18167 outEvts.push( ddo );
18170 oldOvers[i] = true;
18171 delete this.dragOvers[i];
18174 for (var sGroup in dc.groups) {
18176 if ("string" != typeof sGroup) {
18180 for (i in this.ids[sGroup]) {
18181 var oDD = this.ids[sGroup][i];
18182 if (! this.isTypeOfDD(oDD)) {
18186 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18187 if (this.isOverTarget(pt, oDD, this.mode)) {
18188 // look for drop interactions
18190 dropEvts.push( oDD );
18191 // look for drag enter and drag over interactions
18194 // initial drag over: dragEnter fires
18195 if (!oldOvers[oDD.id]) {
18196 enterEvts.push( oDD );
18197 // subsequent drag overs: dragOver fires
18199 overEvts.push( oDD );
18202 this.dragOvers[oDD.id] = oDD;
18210 if (outEvts.length) {
18211 dc.b4DragOut(e, outEvts);
18212 dc.onDragOut(e, outEvts);
18215 if (enterEvts.length) {
18216 dc.onDragEnter(e, enterEvts);
18219 if (overEvts.length) {
18220 dc.b4DragOver(e, overEvts);
18221 dc.onDragOver(e, overEvts);
18224 if (dropEvts.length) {
18225 dc.b4DragDrop(e, dropEvts);
18226 dc.onDragDrop(e, dropEvts);
18230 // fire dragout events
18232 for (i=0, len=outEvts.length; i<len; ++i) {
18233 dc.b4DragOut(e, outEvts[i].id);
18234 dc.onDragOut(e, outEvts[i].id);
18237 // fire enter events
18238 for (i=0,len=enterEvts.length; i<len; ++i) {
18239 // dc.b4DragEnter(e, oDD.id);
18240 dc.onDragEnter(e, enterEvts[i].id);
18243 // fire over events
18244 for (i=0,len=overEvts.length; i<len; ++i) {
18245 dc.b4DragOver(e, overEvts[i].id);
18246 dc.onDragOver(e, overEvts[i].id);
18249 // fire drop events
18250 for (i=0, len=dropEvts.length; i<len; ++i) {
18251 dc.b4DragDrop(e, dropEvts[i].id);
18252 dc.onDragDrop(e, dropEvts[i].id);
18257 // notify about a drop that did not find a target
18258 if (isDrop && !dropEvts.length) {
18259 dc.onInvalidDrop(e);
18265 * Helper function for getting the best match from the list of drag
18266 * and drop objects returned by the drag and drop events when we are
18267 * in INTERSECT mode. It returns either the first object that the
18268 * cursor is over, or the object that has the greatest overlap with
18269 * the dragged element.
18270 * @method getBestMatch
18271 * @param {DragDrop[]} dds The array of drag and drop objects
18273 * @return {DragDrop} The best single match
18276 getBestMatch: function(dds) {
18278 // Return null if the input is not what we expect
18279 //if (!dds || !dds.length || dds.length == 0) {
18281 // If there is only one item, it wins
18282 //} else if (dds.length == 1) {
18284 var len = dds.length;
18289 // Loop through the targeted items
18290 for (var i=0; i<len; ++i) {
18292 // If the cursor is over the object, it wins. If the
18293 // cursor is over multiple matches, the first one we come
18295 if (dd.cursorIsOver) {
18298 // Otherwise the object with the most overlap wins
18301 winner.overlap.getArea() < dd.overlap.getArea()) {
18312 * Refreshes the cache of the top-left and bottom-right points of the
18313 * drag and drop objects in the specified group(s). This is in the
18314 * format that is stored in the drag and drop instance, so typical
18317 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18321 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18323 * @TODO this really should be an indexed array. Alternatively this
18324 * method could accept both.
18325 * @method refreshCache
18326 * @param {Object} groups an associative array of groups to refresh
18329 refreshCache: function(groups) {
18330 for (var sGroup in groups) {
18331 if ("string" != typeof sGroup) {
18334 for (var i in this.ids[sGroup]) {
18335 var oDD = this.ids[sGroup][i];
18337 if (this.isTypeOfDD(oDD)) {
18338 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18339 var loc = this.getLocation(oDD);
18341 this.locationCache[oDD.id] = loc;
18343 delete this.locationCache[oDD.id];
18344 // this will unregister the drag and drop object if
18345 // the element is not in a usable state
18354 * This checks to make sure an element exists and is in the DOM. The
18355 * main purpose is to handle cases where innerHTML is used to remove
18356 * drag and drop objects from the DOM. IE provides an 'unspecified
18357 * error' when trying to access the offsetParent of such an element
18359 * @param {HTMLElement} el the element to check
18360 * @return {boolean} true if the element looks usable
18363 verifyEl: function(el) {
18368 parent = el.offsetParent;
18371 parent = el.offsetParent;
18382 * Returns a Region object containing the drag and drop element's position
18383 * and size, including the padding configured for it
18384 * @method getLocation
18385 * @param {DragDrop} oDD the drag and drop object to get the
18387 * @return {Roo.lib.Region} a Region object representing the total area
18388 * the element occupies, including any padding
18389 * the instance is configured for.
18392 getLocation: function(oDD) {
18393 if (! this.isTypeOfDD(oDD)) {
18397 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18400 pos= Roo.lib.Dom.getXY(el);
18408 x2 = x1 + el.offsetWidth;
18410 y2 = y1 + el.offsetHeight;
18412 t = y1 - oDD.padding[0];
18413 r = x2 + oDD.padding[1];
18414 b = y2 + oDD.padding[2];
18415 l = x1 - oDD.padding[3];
18417 return new Roo.lib.Region( t, r, b, l );
18421 * Checks the cursor location to see if it over the target
18422 * @method isOverTarget
18423 * @param {Roo.lib.Point} pt The point to evaluate
18424 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18425 * @return {boolean} true if the mouse is over the target
18429 isOverTarget: function(pt, oTarget, intersect) {
18430 // use cache if available
18431 var loc = this.locationCache[oTarget.id];
18432 if (!loc || !this.useCache) {
18433 loc = this.getLocation(oTarget);
18434 this.locationCache[oTarget.id] = loc;
18442 oTarget.cursorIsOver = loc.contains( pt );
18444 // DragDrop is using this as a sanity check for the initial mousedown
18445 // in this case we are done. In POINT mode, if the drag obj has no
18446 // contraints, we are also done. Otherwise we need to evaluate the
18447 // location of the target as related to the actual location of the
18448 // dragged element.
18449 var dc = this.dragCurrent;
18450 if (!dc || !dc.getTargetCoord ||
18451 (!intersect && !dc.constrainX && !dc.constrainY)) {
18452 return oTarget.cursorIsOver;
18455 oTarget.overlap = null;
18457 // Get the current location of the drag element, this is the
18458 // location of the mouse event less the delta that represents
18459 // where the original mousedown happened on the element. We
18460 // need to consider constraints and ticks as well.
18461 var pos = dc.getTargetCoord(pt.x, pt.y);
18463 var el = dc.getDragEl();
18464 var curRegion = new Roo.lib.Region( pos.y,
18465 pos.x + el.offsetWidth,
18466 pos.y + el.offsetHeight,
18469 var overlap = curRegion.intersect(loc);
18472 oTarget.overlap = overlap;
18473 return (intersect) ? true : oTarget.cursorIsOver;
18480 * unload event handler
18481 * @method _onUnload
18485 _onUnload: function(e, me) {
18486 Roo.dd.DragDropMgr.unregAll();
18490 * Cleans up the drag and drop events and objects.
18495 unregAll: function() {
18497 if (this.dragCurrent) {
18499 this.dragCurrent = null;
18502 this._execOnAll("unreg", []);
18504 for (i in this.elementCache) {
18505 delete this.elementCache[i];
18508 this.elementCache = {};
18513 * A cache of DOM elements
18514 * @property elementCache
18521 * Get the wrapper for the DOM element specified
18522 * @method getElWrapper
18523 * @param {String} id the id of the element to get
18524 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18526 * @deprecated This wrapper isn't that useful
18529 getElWrapper: function(id) {
18530 var oWrapper = this.elementCache[id];
18531 if (!oWrapper || !oWrapper.el) {
18532 oWrapper = this.elementCache[id] =
18533 new this.ElementWrapper(Roo.getDom(id));
18539 * Returns the actual DOM element
18540 * @method getElement
18541 * @param {String} id the id of the elment to get
18542 * @return {Object} The element
18543 * @deprecated use Roo.getDom instead
18546 getElement: function(id) {
18547 return Roo.getDom(id);
18551 * Returns the style property for the DOM element (i.e.,
18552 * document.getElById(id).style)
18554 * @param {String} id the id of the elment to get
18555 * @return {Object} The style property of the element
18556 * @deprecated use Roo.getDom instead
18559 getCss: function(id) {
18560 var el = Roo.getDom(id);
18561 return (el) ? el.style : null;
18565 * Inner class for cached elements
18566 * @class DragDropMgr.ElementWrapper
18571 ElementWrapper: function(el) {
18576 this.el = el || null;
18581 this.id = this.el && el.id;
18583 * A reference to the style property
18586 this.css = this.el && el.style;
18590 * Returns the X position of an html element
18592 * @param el the element for which to get the position
18593 * @return {int} the X coordinate
18595 * @deprecated use Roo.lib.Dom.getX instead
18598 getPosX: function(el) {
18599 return Roo.lib.Dom.getX(el);
18603 * Returns the Y position of an html element
18605 * @param el the element for which to get the position
18606 * @return {int} the Y coordinate
18607 * @deprecated use Roo.lib.Dom.getY instead
18610 getPosY: function(el) {
18611 return Roo.lib.Dom.getY(el);
18615 * Swap two nodes. In IE, we use the native method, for others we
18616 * emulate the IE behavior
18618 * @param n1 the first node to swap
18619 * @param n2 the other node to swap
18622 swapNode: function(n1, n2) {
18626 var p = n2.parentNode;
18627 var s = n2.nextSibling;
18630 p.insertBefore(n1, n2);
18631 } else if (n2 == n1.nextSibling) {
18632 p.insertBefore(n2, n1);
18634 n1.parentNode.replaceChild(n2, n1);
18635 p.insertBefore(n1, s);
18641 * Returns the current scroll position
18642 * @method getScroll
18646 getScroll: function () {
18647 var t, l, dde=document.documentElement, db=document.body;
18648 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18650 l = dde.scrollLeft;
18657 return { top: t, left: l };
18661 * Returns the specified element style property
18663 * @param {HTMLElement} el the element
18664 * @param {string} styleProp the style property
18665 * @return {string} The value of the style property
18666 * @deprecated use Roo.lib.Dom.getStyle
18669 getStyle: function(el, styleProp) {
18670 return Roo.fly(el).getStyle(styleProp);
18674 * Gets the scrollTop
18675 * @method getScrollTop
18676 * @return {int} the document's scrollTop
18679 getScrollTop: function () { return this.getScroll().top; },
18682 * Gets the scrollLeft
18683 * @method getScrollLeft
18684 * @return {int} the document's scrollTop
18687 getScrollLeft: function () { return this.getScroll().left; },
18690 * Sets the x/y position of an element to the location of the
18693 * @param {HTMLElement} moveEl The element to move
18694 * @param {HTMLElement} targetEl The position reference element
18697 moveToEl: function (moveEl, targetEl) {
18698 var aCoord = Roo.lib.Dom.getXY(targetEl);
18699 Roo.lib.Dom.setXY(moveEl, aCoord);
18703 * Numeric array sort function
18704 * @method numericSort
18707 numericSort: function(a, b) { return (a - b); },
18711 * @property _timeoutCount
18718 * Trying to make the load order less important. Without this we get
18719 * an error if this file is loaded before the Event Utility.
18720 * @method _addListeners
18724 _addListeners: function() {
18725 var DDM = Roo.dd.DDM;
18726 if ( Roo.lib.Event && document ) {
18729 if (DDM._timeoutCount > 2000) {
18731 setTimeout(DDM._addListeners, 10);
18732 if (document && document.body) {
18733 DDM._timeoutCount += 1;
18740 * Recursively searches the immediate parent and all child nodes for
18741 * the handle element in order to determine wheter or not it was
18743 * @method handleWasClicked
18744 * @param node the html element to inspect
18747 handleWasClicked: function(node, id) {
18748 if (this.isHandle(id, node.id)) {
18751 // check to see if this is a text node child of the one we want
18752 var p = node.parentNode;
18755 if (this.isHandle(id, p.id)) {
18770 // shorter alias, save a few bytes
18771 Roo.dd.DDM = Roo.dd.DragDropMgr;
18772 Roo.dd.DDM._addListeners();
18776 * Ext JS Library 1.1.1
18777 * Copyright(c) 2006-2007, Ext JS, LLC.
18779 * Originally Released Under LGPL - original licence link has changed is not relivant.
18782 * <script type="text/javascript">
18787 * A DragDrop implementation where the linked element follows the
18788 * mouse cursor during a drag.
18789 * @extends Roo.dd.DragDrop
18791 * @param {String} id the id of the linked element
18792 * @param {String} sGroup the group of related DragDrop items
18793 * @param {object} config an object containing configurable attributes
18794 * Valid properties for DD:
18797 Roo.dd.DD = function(id, sGroup, config) {
18799 this.init(id, sGroup, config);
18803 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18806 * When set to true, the utility automatically tries to scroll the browser
18807 * window wehn a drag and drop element is dragged near the viewport boundary.
18808 * Defaults to true.
18815 * Sets the pointer offset to the distance between the linked element's top
18816 * left corner and the location the element was clicked
18817 * @method autoOffset
18818 * @param {int} iPageX the X coordinate of the click
18819 * @param {int} iPageY the Y coordinate of the click
18821 autoOffset: function(iPageX, iPageY) {
18822 var x = iPageX - this.startPageX;
18823 var y = iPageY - this.startPageY;
18824 this.setDelta(x, y);
18828 * Sets the pointer offset. You can call this directly to force the
18829 * offset to be in a particular location (e.g., pass in 0,0 to set it
18830 * to the center of the object)
18832 * @param {int} iDeltaX the distance from the left
18833 * @param {int} iDeltaY the distance from the top
18835 setDelta: function(iDeltaX, iDeltaY) {
18836 this.deltaX = iDeltaX;
18837 this.deltaY = iDeltaY;
18841 * Sets the drag element to the location of the mousedown or click event,
18842 * maintaining the cursor location relative to the location on the element
18843 * that was clicked. Override this if you want to place the element in a
18844 * location other than where the cursor is.
18845 * @method setDragElPos
18846 * @param {int} iPageX the X coordinate of the mousedown or drag event
18847 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18849 setDragElPos: function(iPageX, iPageY) {
18850 // the first time we do this, we are going to check to make sure
18851 // the element has css positioning
18853 var el = this.getDragEl();
18854 this.alignElWithMouse(el, iPageX, iPageY);
18858 * Sets the element to the location of the mousedown or click event,
18859 * maintaining the cursor location relative to the location on the element
18860 * that was clicked. Override this if you want to place the element in a
18861 * location other than where the cursor is.
18862 * @method alignElWithMouse
18863 * @param {HTMLElement} el the element to move
18864 * @param {int} iPageX the X coordinate of the mousedown or drag event
18865 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18867 alignElWithMouse: function(el, iPageX, iPageY) {
18868 var oCoord = this.getTargetCoord(iPageX, iPageY);
18869 var fly = el.dom ? el : Roo.fly(el);
18870 if (!this.deltaSetXY) {
18871 var aCoord = [oCoord.x, oCoord.y];
18873 var newLeft = fly.getLeft(true);
18874 var newTop = fly.getTop(true);
18875 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
18877 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
18880 this.cachePosition(oCoord.x, oCoord.y);
18881 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
18886 * Saves the most recent position so that we can reset the constraints and
18887 * tick marks on-demand. We need to know this so that we can calculate the
18888 * number of pixels the element is offset from its original position.
18889 * @method cachePosition
18890 * @param iPageX the current x position (optional, this just makes it so we
18891 * don't have to look it up again)
18892 * @param iPageY the current y position (optional, this just makes it so we
18893 * don't have to look it up again)
18895 cachePosition: function(iPageX, iPageY) {
18897 this.lastPageX = iPageX;
18898 this.lastPageY = iPageY;
18900 var aCoord = Roo.lib.Dom.getXY(this.getEl());
18901 this.lastPageX = aCoord[0];
18902 this.lastPageY = aCoord[1];
18907 * Auto-scroll the window if the dragged object has been moved beyond the
18908 * visible window boundary.
18909 * @method autoScroll
18910 * @param {int} x the drag element's x position
18911 * @param {int} y the drag element's y position
18912 * @param {int} h the height of the drag element
18913 * @param {int} w the width of the drag element
18916 autoScroll: function(x, y, h, w) {
18919 // The client height
18920 var clientH = Roo.lib.Dom.getViewWidth();
18922 // The client width
18923 var clientW = Roo.lib.Dom.getViewHeight();
18925 // The amt scrolled down
18926 var st = this.DDM.getScrollTop();
18928 // The amt scrolled right
18929 var sl = this.DDM.getScrollLeft();
18931 // Location of the bottom of the element
18934 // Location of the right of the element
18937 // The distance from the cursor to the bottom of the visible area,
18938 // adjusted so that we don't scroll if the cursor is beyond the
18939 // element drag constraints
18940 var toBot = (clientH + st - y - this.deltaY);
18942 // The distance from the cursor to the right of the visible area
18943 var toRight = (clientW + sl - x - this.deltaX);
18946 // How close to the edge the cursor must be before we scroll
18947 // var thresh = (document.all) ? 100 : 40;
18950 // How many pixels to scroll per autoscroll op. This helps to reduce
18951 // clunky scrolling. IE is more sensitive about this ... it needs this
18952 // value to be higher.
18953 var scrAmt = (document.all) ? 80 : 30;
18955 // Scroll down if we are near the bottom of the visible page and the
18956 // obj extends below the crease
18957 if ( bot > clientH && toBot < thresh ) {
18958 window.scrollTo(sl, st + scrAmt);
18961 // Scroll up if the window is scrolled down and the top of the object
18962 // goes above the top border
18963 if ( y < st && st > 0 && y - st < thresh ) {
18964 window.scrollTo(sl, st - scrAmt);
18967 // Scroll right if the obj is beyond the right border and the cursor is
18968 // near the border.
18969 if ( right > clientW && toRight < thresh ) {
18970 window.scrollTo(sl + scrAmt, st);
18973 // Scroll left if the window has been scrolled to the right and the obj
18974 // extends past the left border
18975 if ( x < sl && sl > 0 && x - sl < thresh ) {
18976 window.scrollTo(sl - scrAmt, st);
18982 * Finds the location the element should be placed if we want to move
18983 * it to where the mouse location less the click offset would place us.
18984 * @method getTargetCoord
18985 * @param {int} iPageX the X coordinate of the click
18986 * @param {int} iPageY the Y coordinate of the click
18987 * @return an object that contains the coordinates (Object.x and Object.y)
18990 getTargetCoord: function(iPageX, iPageY) {
18993 var x = iPageX - this.deltaX;
18994 var y = iPageY - this.deltaY;
18996 if (this.constrainX) {
18997 if (x < this.minX) { x = this.minX; }
18998 if (x > this.maxX) { x = this.maxX; }
19001 if (this.constrainY) {
19002 if (y < this.minY) { y = this.minY; }
19003 if (y > this.maxY) { y = this.maxY; }
19006 x = this.getTick(x, this.xTicks);
19007 y = this.getTick(y, this.yTicks);
19014 * Sets up config options specific to this class. Overrides
19015 * Roo.dd.DragDrop, but all versions of this method through the
19016 * inheritance chain are called
19018 applyConfig: function() {
19019 Roo.dd.DD.superclass.applyConfig.call(this);
19020 this.scroll = (this.config.scroll !== false);
19024 * Event that fires prior to the onMouseDown event. Overrides
19027 b4MouseDown: function(e) {
19028 // this.resetConstraints();
19029 this.autoOffset(e.getPageX(),
19034 * Event that fires prior to the onDrag event. Overrides
19037 b4Drag: function(e) {
19038 this.setDragElPos(e.getPageX(),
19042 toString: function() {
19043 return ("DD " + this.id);
19046 //////////////////////////////////////////////////////////////////////////
19047 // Debugging ygDragDrop events that can be overridden
19048 //////////////////////////////////////////////////////////////////////////
19050 startDrag: function(x, y) {
19053 onDrag: function(e) {
19056 onDragEnter: function(e, id) {
19059 onDragOver: function(e, id) {
19062 onDragOut: function(e, id) {
19065 onDragDrop: function(e, id) {
19068 endDrag: function(e) {
19075 * Ext JS Library 1.1.1
19076 * Copyright(c) 2006-2007, Ext JS, LLC.
19078 * Originally Released Under LGPL - original licence link has changed is not relivant.
19081 * <script type="text/javascript">
19085 * @class Roo.dd.DDProxy
19086 * A DragDrop implementation that inserts an empty, bordered div into
19087 * the document that follows the cursor during drag operations. At the time of
19088 * the click, the frame div is resized to the dimensions of the linked html
19089 * element, and moved to the exact location of the linked element.
19091 * References to the "frame" element refer to the single proxy element that
19092 * was created to be dragged in place of all DDProxy elements on the
19095 * @extends Roo.dd.DD
19097 * @param {String} id the id of the linked html element
19098 * @param {String} sGroup the group of related DragDrop objects
19099 * @param {object} config an object containing configurable attributes
19100 * Valid properties for DDProxy in addition to those in DragDrop:
19101 * resizeFrame, centerFrame, dragElId
19103 Roo.dd.DDProxy = function(id, sGroup, config) {
19105 this.init(id, sGroup, config);
19111 * The default drag frame div id
19112 * @property Roo.dd.DDProxy.dragElId
19116 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19118 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19121 * By default we resize the drag frame to be the same size as the element
19122 * we want to drag (this is to get the frame effect). We can turn it off
19123 * if we want a different behavior.
19124 * @property resizeFrame
19130 * By default the frame is positioned exactly where the drag element is, so
19131 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19132 * you do not have constraints on the obj is to have the drag frame centered
19133 * around the cursor. Set centerFrame to true for this effect.
19134 * @property centerFrame
19137 centerFrame: false,
19140 * Creates the proxy element if it does not yet exist
19141 * @method createFrame
19143 createFrame: function() {
19145 var body = document.body;
19147 if (!body || !body.firstChild) {
19148 setTimeout( function() { self.createFrame(); }, 50 );
19152 var div = this.getDragEl();
19155 div = document.createElement("div");
19156 div.id = this.dragElId;
19159 s.position = "absolute";
19160 s.visibility = "hidden";
19162 s.border = "2px solid #aaa";
19165 // appendChild can blow up IE if invoked prior to the window load event
19166 // while rendering a table. It is possible there are other scenarios
19167 // that would cause this to happen as well.
19168 body.insertBefore(div, body.firstChild);
19173 * Initialization for the drag frame element. Must be called in the
19174 * constructor of all subclasses
19175 * @method initFrame
19177 initFrame: function() {
19178 this.createFrame();
19181 applyConfig: function() {
19182 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19184 this.resizeFrame = (this.config.resizeFrame !== false);
19185 this.centerFrame = (this.config.centerFrame);
19186 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19190 * Resizes the drag frame to the dimensions of the clicked object, positions
19191 * it over the object, and finally displays it
19192 * @method showFrame
19193 * @param {int} iPageX X click position
19194 * @param {int} iPageY Y click position
19197 showFrame: function(iPageX, iPageY) {
19198 var el = this.getEl();
19199 var dragEl = this.getDragEl();
19200 var s = dragEl.style;
19202 this._resizeProxy();
19204 if (this.centerFrame) {
19205 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19206 Math.round(parseInt(s.height, 10)/2) );
19209 this.setDragElPos(iPageX, iPageY);
19211 Roo.fly(dragEl).show();
19215 * The proxy is automatically resized to the dimensions of the linked
19216 * element when a drag is initiated, unless resizeFrame is set to false
19217 * @method _resizeProxy
19220 _resizeProxy: function() {
19221 if (this.resizeFrame) {
19222 var el = this.getEl();
19223 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19227 // overrides Roo.dd.DragDrop
19228 b4MouseDown: function(e) {
19229 var x = e.getPageX();
19230 var y = e.getPageY();
19231 this.autoOffset(x, y);
19232 this.setDragElPos(x, y);
19235 // overrides Roo.dd.DragDrop
19236 b4StartDrag: function(x, y) {
19237 // show the drag frame
19238 this.showFrame(x, y);
19241 // overrides Roo.dd.DragDrop
19242 b4EndDrag: function(e) {
19243 Roo.fly(this.getDragEl()).hide();
19246 // overrides Roo.dd.DragDrop
19247 // By default we try to move the element to the last location of the frame.
19248 // This is so that the default behavior mirrors that of Roo.dd.DD.
19249 endDrag: function(e) {
19251 var lel = this.getEl();
19252 var del = this.getDragEl();
19254 // Show the drag frame briefly so we can get its position
19255 del.style.visibility = "";
19258 // Hide the linked element before the move to get around a Safari
19260 lel.style.visibility = "hidden";
19261 Roo.dd.DDM.moveToEl(lel, del);
19262 del.style.visibility = "hidden";
19263 lel.style.visibility = "";
19268 beforeMove : function(){
19272 afterDrag : function(){
19276 toString: function() {
19277 return ("DDProxy " + this.id);
19283 * Ext JS Library 1.1.1
19284 * Copyright(c) 2006-2007, Ext JS, LLC.
19286 * Originally Released Under LGPL - original licence link has changed is not relivant.
19289 * <script type="text/javascript">
19293 * @class Roo.dd.DDTarget
19294 * A DragDrop implementation that does not move, but can be a drop
19295 * target. You would get the same result by simply omitting implementation
19296 * for the event callbacks, but this way we reduce the processing cost of the
19297 * event listener and the callbacks.
19298 * @extends Roo.dd.DragDrop
19300 * @param {String} id the id of the element that is a drop target
19301 * @param {String} sGroup the group of related DragDrop objects
19302 * @param {object} config an object containing configurable attributes
19303 * Valid properties for DDTarget in addition to those in
19307 Roo.dd.DDTarget = function(id, sGroup, config) {
19309 this.initTarget(id, sGroup, config);
19311 if (config.listeners || config.events) {
19312 Roo.dd.DragDrop.superclass.constructor.call(this, {
19313 listeners : config.listeners || {},
19314 events : config.events || {}
19319 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19320 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19321 toString: function() {
19322 return ("DDTarget " + this.id);
19327 * Ext JS Library 1.1.1
19328 * Copyright(c) 2006-2007, Ext JS, LLC.
19330 * Originally Released Under LGPL - original licence link has changed is not relivant.
19333 * <script type="text/javascript">
19338 * @class Roo.dd.ScrollManager
19339 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19340 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19343 Roo.dd.ScrollManager = function(){
19344 var ddm = Roo.dd.DragDropMgr;
19351 var onStop = function(e){
19356 var triggerRefresh = function(){
19357 if(ddm.dragCurrent){
19358 ddm.refreshCache(ddm.dragCurrent.groups);
19362 var doScroll = function(){
19363 if(ddm.dragCurrent){
19364 var dds = Roo.dd.ScrollManager;
19366 if(proc.el.scroll(proc.dir, dds.increment)){
19370 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19375 var clearProc = function(){
19377 clearInterval(proc.id);
19384 var startProc = function(el, dir){
19385 Roo.log('scroll startproc');
19389 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19392 var onFire = function(e, isDrop){
19394 if(isDrop || !ddm.dragCurrent){ return; }
19395 var dds = Roo.dd.ScrollManager;
19396 if(!dragEl || dragEl != ddm.dragCurrent){
19397 dragEl = ddm.dragCurrent;
19398 // refresh regions on drag start
19399 dds.refreshCache();
19402 var xy = Roo.lib.Event.getXY(e);
19403 var pt = new Roo.lib.Point(xy[0], xy[1]);
19404 for(var id in els){
19405 var el = els[id], r = el._region;
19406 if(r && r.contains(pt) && el.isScrollable()){
19407 if(r.bottom - pt.y <= dds.thresh){
19409 startProc(el, "down");
19412 }else if(r.right - pt.x <= dds.thresh){
19414 startProc(el, "left");
19417 }else if(pt.y - r.top <= dds.thresh){
19419 startProc(el, "up");
19422 }else if(pt.x - r.left <= dds.thresh){
19424 startProc(el, "right");
19433 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19434 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19438 * Registers new overflow element(s) to auto scroll
19439 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19441 register : function(el){
19442 if(el instanceof Array){
19443 for(var i = 0, len = el.length; i < len; i++) {
19444 this.register(el[i]);
19450 Roo.dd.ScrollManager.els = els;
19454 * Unregisters overflow element(s) so they are no longer scrolled
19455 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19457 unregister : function(el){
19458 if(el instanceof Array){
19459 for(var i = 0, len = el.length; i < len; i++) {
19460 this.unregister(el[i]);
19469 * The number of pixels from the edge of a container the pointer needs to be to
19470 * trigger scrolling (defaults to 25)
19476 * The number of pixels to scroll in each scroll increment (defaults to 50)
19482 * The frequency of scrolls in milliseconds (defaults to 500)
19488 * True to animate the scroll (defaults to true)
19494 * The animation duration in seconds -
19495 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19501 * Manually trigger a cache refresh.
19503 refreshCache : function(){
19504 for(var id in els){
19505 if(typeof els[id] == 'object'){ // for people extending the object prototype
19506 els[id]._region = els[id].getRegion();
19513 * Ext JS Library 1.1.1
19514 * Copyright(c) 2006-2007, Ext JS, LLC.
19516 * Originally Released Under LGPL - original licence link has changed is not relivant.
19519 * <script type="text/javascript">
19524 * @class Roo.dd.Registry
19525 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19526 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19529 Roo.dd.Registry = function(){
19532 var autoIdSeed = 0;
19534 var getId = function(el, autogen){
19535 if(typeof el == "string"){
19539 if(!id && autogen !== false){
19540 id = "roodd-" + (++autoIdSeed);
19548 * Register a drag drop element
19549 * @param {String|HTMLElement} element The id or DOM node to register
19550 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19551 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19552 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19553 * populated in the data object (if applicable):
19555 Value Description<br />
19556 --------- ------------------------------------------<br />
19557 handles Array of DOM nodes that trigger dragging<br />
19558 for the element being registered<br />
19559 isHandle True if the element passed in triggers<br />
19560 dragging itself, else false
19563 register : function(el, data){
19565 if(typeof el == "string"){
19566 el = document.getElementById(el);
19569 elements[getId(el)] = data;
19570 if(data.isHandle !== false){
19571 handles[data.ddel.id] = data;
19574 var hs = data.handles;
19575 for(var i = 0, len = hs.length; i < len; i++){
19576 handles[getId(hs[i])] = data;
19582 * Unregister a drag drop element
19583 * @param {String|HTMLElement} element The id or DOM node to unregister
19585 unregister : function(el){
19586 var id = getId(el, false);
19587 var data = elements[id];
19589 delete elements[id];
19591 var hs = data.handles;
19592 for(var i = 0, len = hs.length; i < len; i++){
19593 delete handles[getId(hs[i], false)];
19600 * Returns the handle registered for a DOM Node by id
19601 * @param {String|HTMLElement} id The DOM node or id to look up
19602 * @return {Object} handle The custom handle data
19604 getHandle : function(id){
19605 if(typeof id != "string"){ // must be element?
19608 return handles[id];
19612 * Returns the handle that is registered for the DOM node that is the target of the event
19613 * @param {Event} e The event
19614 * @return {Object} handle The custom handle data
19616 getHandleFromEvent : function(e){
19617 var t = Roo.lib.Event.getTarget(e);
19618 return t ? handles[t.id] : null;
19622 * Returns a custom data object that is registered for a DOM node by id
19623 * @param {String|HTMLElement} id The DOM node or id to look up
19624 * @return {Object} data The custom data
19626 getTarget : function(id){
19627 if(typeof id != "string"){ // must be element?
19630 return elements[id];
19634 * Returns a custom data object that is registered for the DOM node that is the target of the event
19635 * @param {Event} e The event
19636 * @return {Object} data The custom data
19638 getTargetFromEvent : function(e){
19639 var t = Roo.lib.Event.getTarget(e);
19640 return t ? elements[t.id] || handles[t.id] : null;
19645 * Ext JS Library 1.1.1
19646 * Copyright(c) 2006-2007, Ext JS, LLC.
19648 * Originally Released Under LGPL - original licence link has changed is not relivant.
19651 * <script type="text/javascript">
19656 * @class Roo.dd.StatusProxy
19657 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19658 * default drag proxy used by all Roo.dd components.
19660 * @param {Object} config
19662 Roo.dd.StatusProxy = function(config){
19663 Roo.apply(this, config);
19664 this.id = this.id || Roo.id();
19665 this.el = new Roo.Layer({
19667 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19668 {tag: "div", cls: "x-dd-drop-icon"},
19669 {tag: "div", cls: "x-dd-drag-ghost"}
19672 shadow: !config || config.shadow !== false
19674 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19675 this.dropStatus = this.dropNotAllowed;
19678 Roo.dd.StatusProxy.prototype = {
19680 * @cfg {String} dropAllowed
19681 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19683 dropAllowed : "x-dd-drop-ok",
19685 * @cfg {String} dropNotAllowed
19686 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19688 dropNotAllowed : "x-dd-drop-nodrop",
19691 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19692 * over the current target element.
19693 * @param {String} cssClass The css class for the new drop status indicator image
19695 setStatus : function(cssClass){
19696 cssClass = cssClass || this.dropNotAllowed;
19697 if(this.dropStatus != cssClass){
19698 this.el.replaceClass(this.dropStatus, cssClass);
19699 this.dropStatus = cssClass;
19704 * Resets the status indicator to the default dropNotAllowed value
19705 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19707 reset : function(clearGhost){
19708 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19709 this.dropStatus = this.dropNotAllowed;
19711 this.ghost.update("");
19716 * Updates the contents of the ghost element
19717 * @param {String} html The html that will replace the current innerHTML of the ghost element
19719 update : function(html){
19720 if(typeof html == "string"){
19721 this.ghost.update(html);
19723 this.ghost.update("");
19724 html.style.margin = "0";
19725 this.ghost.dom.appendChild(html);
19727 // ensure float = none set?? cant remember why though.
19728 var el = this.ghost.dom.firstChild;
19730 Roo.fly(el).setStyle('float', 'none');
19735 * Returns the underlying proxy {@link Roo.Layer}
19736 * @return {Roo.Layer} el
19738 getEl : function(){
19743 * Returns the ghost element
19744 * @return {Roo.Element} el
19746 getGhost : function(){
19752 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19754 hide : function(clear){
19762 * Stops the repair animation if it's currently running
19765 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19771 * Displays this proxy
19778 * Force the Layer to sync its shadow and shim positions to the element
19785 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19786 * invalid drop operation by the item being dragged.
19787 * @param {Array} xy The XY position of the element ([x, y])
19788 * @param {Function} callback The function to call after the repair is complete
19789 * @param {Object} scope The scope in which to execute the callback
19791 repair : function(xy, callback, scope){
19792 this.callback = callback;
19793 this.scope = scope;
19794 if(xy && this.animRepair !== false){
19795 this.el.addClass("x-dd-drag-repair");
19796 this.el.hideUnders(true);
19797 this.anim = this.el.shift({
19798 duration: this.repairDuration || .5,
19802 callback: this.afterRepair,
19806 this.afterRepair();
19811 afterRepair : function(){
19813 if(typeof this.callback == "function"){
19814 this.callback.call(this.scope || this);
19816 this.callback = null;
19821 * Ext JS Library 1.1.1
19822 * Copyright(c) 2006-2007, Ext JS, LLC.
19824 * Originally Released Under LGPL - original licence link has changed is not relivant.
19827 * <script type="text/javascript">
19831 * @class Roo.dd.DragSource
19832 * @extends Roo.dd.DDProxy
19833 * A simple class that provides the basic implementation needed to make any element draggable.
19835 * @param {String/HTMLElement/Element} el The container element
19836 * @param {Object} config
19838 Roo.dd.DragSource = function(el, config){
19839 this.el = Roo.get(el);
19840 this.dragData = {};
19842 Roo.apply(this, config);
19845 this.proxy = new Roo.dd.StatusProxy();
19848 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
19849 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
19851 this.dragging = false;
19854 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
19856 * @cfg {String} dropAllowed
19857 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
19859 dropAllowed : "x-dd-drop-ok",
19861 * @cfg {String} dropNotAllowed
19862 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
19864 dropNotAllowed : "x-dd-drop-nodrop",
19867 * Returns the data object associated with this drag source
19868 * @return {Object} data An object containing arbitrary data
19870 getDragData : function(e){
19871 return this.dragData;
19875 onDragEnter : function(e, id){
19876 var target = Roo.dd.DragDropMgr.getDDById(id);
19877 this.cachedTarget = target;
19878 if(this.beforeDragEnter(target, e, id) !== false){
19879 if(target.isNotifyTarget){
19880 var status = target.notifyEnter(this, e, this.dragData);
19881 this.proxy.setStatus(status);
19883 this.proxy.setStatus(this.dropAllowed);
19886 if(this.afterDragEnter){
19888 * An empty function by default, but provided so that you can perform a custom action
19889 * when the dragged item enters the drop target by providing an implementation.
19890 * @param {Roo.dd.DragDrop} target The drop target
19891 * @param {Event} e The event object
19892 * @param {String} id The id of the dragged element
19893 * @method afterDragEnter
19895 this.afterDragEnter(target, e, id);
19901 * An empty function by default, but provided so that you can perform a custom action
19902 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
19903 * @param {Roo.dd.DragDrop} target The drop target
19904 * @param {Event} e The event object
19905 * @param {String} id The id of the dragged element
19906 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19908 beforeDragEnter : function(target, e, id){
19913 alignElWithMouse: function() {
19914 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
19919 onDragOver : function(e, id){
19920 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19921 if(this.beforeDragOver(target, e, id) !== false){
19922 if(target.isNotifyTarget){
19923 var status = target.notifyOver(this, e, this.dragData);
19924 this.proxy.setStatus(status);
19927 if(this.afterDragOver){
19929 * An empty function by default, but provided so that you can perform a custom action
19930 * while the dragged item is over the drop target by providing an implementation.
19931 * @param {Roo.dd.DragDrop} target The drop target
19932 * @param {Event} e The event object
19933 * @param {String} id The id of the dragged element
19934 * @method afterDragOver
19936 this.afterDragOver(target, e, id);
19942 * An empty function by default, but provided so that you can perform a custom action
19943 * while the dragged item is over the drop target and optionally cancel the onDragOver.
19944 * @param {Roo.dd.DragDrop} target The drop target
19945 * @param {Event} e The event object
19946 * @param {String} id The id of the dragged element
19947 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19949 beforeDragOver : function(target, e, id){
19954 onDragOut : function(e, id){
19955 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19956 if(this.beforeDragOut(target, e, id) !== false){
19957 if(target.isNotifyTarget){
19958 target.notifyOut(this, e, this.dragData);
19960 this.proxy.reset();
19961 if(this.afterDragOut){
19963 * An empty function by default, but provided so that you can perform a custom action
19964 * after the dragged item is dragged out of the target without dropping.
19965 * @param {Roo.dd.DragDrop} target The drop target
19966 * @param {Event} e The event object
19967 * @param {String} id The id of the dragged element
19968 * @method afterDragOut
19970 this.afterDragOut(target, e, id);
19973 this.cachedTarget = null;
19977 * An empty function by default, but provided so that you can perform a custom action before the dragged
19978 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
19979 * @param {Roo.dd.DragDrop} target The drop target
19980 * @param {Event} e The event object
19981 * @param {String} id The id of the dragged element
19982 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19984 beforeDragOut : function(target, e, id){
19989 onDragDrop : function(e, id){
19990 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19991 if(this.beforeDragDrop(target, e, id) !== false){
19992 if(target.isNotifyTarget){
19993 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
19994 this.onValidDrop(target, e, id);
19996 this.onInvalidDrop(target, e, id);
19999 this.onValidDrop(target, e, id);
20002 if(this.afterDragDrop){
20004 * An empty function by default, but provided so that you can perform a custom action
20005 * after a valid drag drop has occurred by providing an implementation.
20006 * @param {Roo.dd.DragDrop} target The drop target
20007 * @param {Event} e The event object
20008 * @param {String} id The id of the dropped element
20009 * @method afterDragDrop
20011 this.afterDragDrop(target, e, id);
20014 delete this.cachedTarget;
20018 * An empty function by default, but provided so that you can perform a custom action before the dragged
20019 * item is dropped onto the target and optionally cancel the onDragDrop.
20020 * @param {Roo.dd.DragDrop} target The drop target
20021 * @param {Event} e The event object
20022 * @param {String} id The id of the dragged element
20023 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20025 beforeDragDrop : function(target, e, id){
20030 onValidDrop : function(target, e, id){
20032 if(this.afterValidDrop){
20034 * An empty function by default, but provided so that you can perform a custom action
20035 * after a valid drop has occurred by providing an implementation.
20036 * @param {Object} target The target DD
20037 * @param {Event} e The event object
20038 * @param {String} id The id of the dropped element
20039 * @method afterInvalidDrop
20041 this.afterValidDrop(target, e, id);
20046 getRepairXY : function(e, data){
20047 return this.el.getXY();
20051 onInvalidDrop : function(target, e, id){
20052 this.beforeInvalidDrop(target, e, id);
20053 if(this.cachedTarget){
20054 if(this.cachedTarget.isNotifyTarget){
20055 this.cachedTarget.notifyOut(this, e, this.dragData);
20057 this.cacheTarget = null;
20059 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20061 if(this.afterInvalidDrop){
20063 * An empty function by default, but provided so that you can perform a custom action
20064 * after an invalid drop has occurred by providing an implementation.
20065 * @param {Event} e The event object
20066 * @param {String} id The id of the dropped element
20067 * @method afterInvalidDrop
20069 this.afterInvalidDrop(e, id);
20074 afterRepair : function(){
20076 this.el.highlight(this.hlColor || "c3daf9");
20078 this.dragging = false;
20082 * An empty function by default, but provided so that you can perform a custom action after an invalid
20083 * drop has occurred.
20084 * @param {Roo.dd.DragDrop} target The drop target
20085 * @param {Event} e The event object
20086 * @param {String} id The id of the dragged element
20087 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20089 beforeInvalidDrop : function(target, e, id){
20094 handleMouseDown : function(e){
20095 if(this.dragging) {
20098 var data = this.getDragData(e);
20099 if(data && this.onBeforeDrag(data, e) !== false){
20100 this.dragData = data;
20102 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20107 * An empty function by default, but provided so that you can perform a custom action before the initial
20108 * drag event begins and optionally cancel it.
20109 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20110 * @param {Event} e The event object
20111 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20113 onBeforeDrag : function(data, e){
20118 * An empty function by default, but provided so that you can perform a custom action once the initial
20119 * drag event has begun. The drag cannot be canceled from this function.
20120 * @param {Number} x The x position of the click on the dragged object
20121 * @param {Number} y The y position of the click on the dragged object
20123 onStartDrag : Roo.emptyFn,
20125 // private - YUI override
20126 startDrag : function(x, y){
20127 this.proxy.reset();
20128 this.dragging = true;
20129 this.proxy.update("");
20130 this.onInitDrag(x, y);
20135 onInitDrag : function(x, y){
20136 var clone = this.el.dom.cloneNode(true);
20137 clone.id = Roo.id(); // prevent duplicate ids
20138 this.proxy.update(clone);
20139 this.onStartDrag(x, y);
20144 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20145 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20147 getProxy : function(){
20152 * Hides the drag source's {@link Roo.dd.StatusProxy}
20154 hideProxy : function(){
20156 this.proxy.reset(true);
20157 this.dragging = false;
20161 triggerCacheRefresh : function(){
20162 Roo.dd.DDM.refreshCache(this.groups);
20165 // private - override to prevent hiding
20166 b4EndDrag: function(e) {
20169 // private - override to prevent moving
20170 endDrag : function(e){
20171 this.onEndDrag(this.dragData, e);
20175 onEndDrag : function(data, e){
20178 // private - pin to cursor
20179 autoOffset : function(x, y) {
20180 this.setDelta(-12, -20);
20184 * Ext JS Library 1.1.1
20185 * Copyright(c) 2006-2007, Ext JS, LLC.
20187 * Originally Released Under LGPL - original licence link has changed is not relivant.
20190 * <script type="text/javascript">
20195 * @class Roo.dd.DropTarget
20196 * @extends Roo.dd.DDTarget
20197 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20198 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20200 * @param {String/HTMLElement/Element} el The container element
20201 * @param {Object} config
20203 Roo.dd.DropTarget = function(el, config){
20204 this.el = Roo.get(el);
20206 var listeners = false; ;
20207 if (config && config.listeners) {
20208 listeners= config.listeners;
20209 delete config.listeners;
20211 Roo.apply(this, config);
20213 if(this.containerScroll){
20214 Roo.dd.ScrollManager.register(this.el);
20218 * @scope Roo.dd.DropTarget
20223 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20224 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20225 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20227 * IMPORTANT : it should set this.overClass and this.dropAllowed
20229 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20230 * @param {Event} e The event
20231 * @param {Object} data An object containing arbitrary data supplied by the drag source
20237 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20238 * This method will be called on every mouse movement while the drag source is over the drop target.
20239 * This default implementation simply returns the dropAllowed config value.
20241 * IMPORTANT : it should set this.dropAllowed
20243 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20244 * @param {Event} e The event
20245 * @param {Object} data An object containing arbitrary data supplied by the drag source
20251 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20252 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20253 * overClass (if any) from the drop element.
20255 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20256 * @param {Event} e The event
20257 * @param {Object} data An object containing arbitrary data supplied by the drag source
20263 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20264 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20265 * implementation that does something to process the drop event and returns true so that the drag source's
20266 * repair action does not run.
20268 * IMPORTANT : it should set this.success
20270 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20271 * @param {Event} e The event
20272 * @param {Object} data An object containing arbitrary data supplied by the drag source
20278 Roo.dd.DropTarget.superclass.constructor.call( this,
20280 this.ddGroup || this.group,
20283 listeners : listeners || {}
20291 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20293 * @cfg {String} overClass
20294 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20297 * @cfg {String} ddGroup
20298 * The drag drop group to handle drop events for
20302 * @cfg {String} dropAllowed
20303 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20305 dropAllowed : "x-dd-drop-ok",
20307 * @cfg {String} dropNotAllowed
20308 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20310 dropNotAllowed : "x-dd-drop-nodrop",
20312 * @cfg {boolean} success
20313 * set this after drop listener..
20317 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20318 * if the drop point is valid for over/enter..
20325 isNotifyTarget : true,
20330 notifyEnter : function(dd, e, data)
20333 this.fireEvent('enter', dd, e, data);
20334 if(this.overClass){
20335 this.el.addClass(this.overClass);
20337 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20338 this.valid ? this.dropAllowed : this.dropNotAllowed
20345 notifyOver : function(dd, e, data)
20348 this.fireEvent('over', dd, e, data);
20349 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20350 this.valid ? this.dropAllowed : this.dropNotAllowed
20357 notifyOut : function(dd, e, data)
20359 this.fireEvent('out', dd, e, data);
20360 if(this.overClass){
20361 this.el.removeClass(this.overClass);
20368 notifyDrop : function(dd, e, data)
20370 this.success = false;
20371 this.fireEvent('drop', dd, e, data);
20372 return this.success;
20376 * Ext JS Library 1.1.1
20377 * Copyright(c) 2006-2007, Ext JS, LLC.
20379 * Originally Released Under LGPL - original licence link has changed is not relivant.
20382 * <script type="text/javascript">
20387 * @class Roo.dd.DragZone
20388 * @extends Roo.dd.DragSource
20389 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20390 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20392 * @param {String/HTMLElement/Element} el The container element
20393 * @param {Object} config
20395 Roo.dd.DragZone = function(el, config){
20396 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20397 if(this.containerScroll){
20398 Roo.dd.ScrollManager.register(this.el);
20402 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20404 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20405 * for auto scrolling during drag operations.
20408 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20409 * method after a failed drop (defaults to "c3daf9" - light blue)
20413 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20414 * for a valid target to drag based on the mouse down. Override this method
20415 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20416 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20417 * @param {EventObject} e The mouse down event
20418 * @return {Object} The dragData
20420 getDragData : function(e){
20421 return Roo.dd.Registry.getHandleFromEvent(e);
20425 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20426 * this.dragData.ddel
20427 * @param {Number} x The x position of the click on the dragged object
20428 * @param {Number} y The y position of the click on the dragged object
20429 * @return {Boolean} true to continue the drag, false to cancel
20431 onInitDrag : function(x, y){
20432 this.proxy.update(this.dragData.ddel.cloneNode(true));
20433 this.onStartDrag(x, y);
20438 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20440 afterRepair : function(){
20442 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20444 this.dragging = false;
20448 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20449 * the XY of this.dragData.ddel
20450 * @param {EventObject} e The mouse up event
20451 * @return {Array} The xy location (e.g. [100, 200])
20453 getRepairXY : function(e){
20454 return Roo.Element.fly(this.dragData.ddel).getXY();
20458 * Ext JS Library 1.1.1
20459 * Copyright(c) 2006-2007, Ext JS, LLC.
20461 * Originally Released Under LGPL - original licence link has changed is not relivant.
20464 * <script type="text/javascript">
20467 * @class Roo.dd.DropZone
20468 * @extends Roo.dd.DropTarget
20469 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20470 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20472 * @param {String/HTMLElement/Element} el The container element
20473 * @param {Object} config
20475 Roo.dd.DropZone = function(el, config){
20476 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20479 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20481 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20482 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20483 * provide your own custom lookup.
20484 * @param {Event} e The event
20485 * @return {Object} data The custom data
20487 getTargetFromEvent : function(e){
20488 return Roo.dd.Registry.getTargetFromEvent(e);
20492 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20493 * that it has registered. This method has no default implementation and should be overridden to provide
20494 * node-specific processing if necessary.
20495 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20496 * {@link #getTargetFromEvent} for this node)
20497 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20498 * @param {Event} e The event
20499 * @param {Object} data An object containing arbitrary data supplied by the drag source
20501 onNodeEnter : function(n, dd, e, data){
20506 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20507 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20508 * overridden to provide the proper feedback.
20509 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20510 * {@link #getTargetFromEvent} for this node)
20511 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20512 * @param {Event} e The event
20513 * @param {Object} data An object containing arbitrary data supplied by the drag source
20514 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20515 * underlying {@link Roo.dd.StatusProxy} can be updated
20517 onNodeOver : function(n, dd, e, data){
20518 return this.dropAllowed;
20522 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20523 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20524 * node-specific processing if necessary.
20525 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20526 * {@link #getTargetFromEvent} for this node)
20527 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20528 * @param {Event} e The event
20529 * @param {Object} data An object containing arbitrary data supplied by the drag source
20531 onNodeOut : function(n, dd, e, data){
20536 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20537 * the drop node. The default implementation returns false, so it should be overridden to provide the
20538 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20539 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20540 * {@link #getTargetFromEvent} for this node)
20541 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20542 * @param {Event} e The event
20543 * @param {Object} data An object containing arbitrary data supplied by the drag source
20544 * @return {Boolean} True if the drop was valid, else false
20546 onNodeDrop : function(n, dd, e, data){
20551 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20552 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20553 * it should be overridden to provide the proper feedback if necessary.
20554 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20555 * @param {Event} e The event
20556 * @param {Object} data An object containing arbitrary data supplied by the drag source
20557 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20558 * underlying {@link Roo.dd.StatusProxy} can be updated
20560 onContainerOver : function(dd, e, data){
20561 return this.dropNotAllowed;
20565 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20566 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20567 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20568 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20569 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20570 * @param {Event} e The event
20571 * @param {Object} data An object containing arbitrary data supplied by the drag source
20572 * @return {Boolean} True if the drop was valid, else false
20574 onContainerDrop : function(dd, e, data){
20579 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20580 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20581 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20582 * you should override this method and provide a custom implementation.
20583 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20584 * @param {Event} e The event
20585 * @param {Object} data An object containing arbitrary data supplied by the drag source
20586 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20587 * underlying {@link Roo.dd.StatusProxy} can be updated
20589 notifyEnter : function(dd, e, data){
20590 return this.dropNotAllowed;
20594 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20595 * This method will be called on every mouse movement while the drag source is over the drop zone.
20596 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20597 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20598 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20599 * registered node, it will call {@link #onContainerOver}.
20600 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20601 * @param {Event} e The event
20602 * @param {Object} data An object containing arbitrary data supplied by the drag source
20603 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20604 * underlying {@link Roo.dd.StatusProxy} can be updated
20606 notifyOver : function(dd, e, data){
20607 var n = this.getTargetFromEvent(e);
20608 if(!n){ // not over valid drop target
20609 if(this.lastOverNode){
20610 this.onNodeOut(this.lastOverNode, dd, e, data);
20611 this.lastOverNode = null;
20613 return this.onContainerOver(dd, e, data);
20615 if(this.lastOverNode != n){
20616 if(this.lastOverNode){
20617 this.onNodeOut(this.lastOverNode, dd, e, data);
20619 this.onNodeEnter(n, dd, e, data);
20620 this.lastOverNode = n;
20622 return this.onNodeOver(n, dd, e, data);
20626 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20627 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20628 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20629 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20630 * @param {Event} e The event
20631 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20633 notifyOut : function(dd, e, data){
20634 if(this.lastOverNode){
20635 this.onNodeOut(this.lastOverNode, dd, e, data);
20636 this.lastOverNode = null;
20641 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20642 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20643 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20644 * otherwise it will call {@link #onContainerDrop}.
20645 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20646 * @param {Event} e The event
20647 * @param {Object} data An object containing arbitrary data supplied by the drag source
20648 * @return {Boolean} True if the drop was valid, else false
20650 notifyDrop : function(dd, e, data){
20651 if(this.lastOverNode){
20652 this.onNodeOut(this.lastOverNode, dd, e, data);
20653 this.lastOverNode = null;
20655 var n = this.getTargetFromEvent(e);
20657 this.onNodeDrop(n, dd, e, data) :
20658 this.onContainerDrop(dd, e, data);
20662 triggerCacheRefresh : function(){
20663 Roo.dd.DDM.refreshCache(this.groups);
20667 * Ext JS Library 1.1.1
20668 * Copyright(c) 2006-2007, Ext JS, LLC.
20670 * Originally Released Under LGPL - original licence link has changed is not relivant.
20673 * <script type="text/javascript">
20678 * @class Roo.data.SortTypes
20680 * Defines the default sorting (casting?) comparison functions used when sorting data.
20682 Roo.data.SortTypes = {
20684 * Default sort that does nothing
20685 * @param {Mixed} s The value being converted
20686 * @return {Mixed} The comparison value
20688 none : function(s){
20693 * The regular expression used to strip tags
20697 stripTagsRE : /<\/?[^>]+>/gi,
20700 * Strips all HTML tags to sort on text only
20701 * @param {Mixed} s The value being converted
20702 * @return {String} The comparison value
20704 asText : function(s){
20705 return String(s).replace(this.stripTagsRE, "");
20709 * Strips all HTML tags to sort on text only - Case insensitive
20710 * @param {Mixed} s The value being converted
20711 * @return {String} The comparison value
20713 asUCText : function(s){
20714 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20718 * Case insensitive string
20719 * @param {Mixed} s The value being converted
20720 * @return {String} The comparison value
20722 asUCString : function(s) {
20723 return String(s).toUpperCase();
20728 * @param {Mixed} s The value being converted
20729 * @return {Number} The comparison value
20731 asDate : function(s) {
20735 if(s instanceof Date){
20736 return s.getTime();
20738 return Date.parse(String(s));
20743 * @param {Mixed} s The value being converted
20744 * @return {Float} The comparison value
20746 asFloat : function(s) {
20747 var val = parseFloat(String(s).replace(/,/g, ""));
20748 if(isNaN(val)) val = 0;
20754 * @param {Mixed} s The value being converted
20755 * @return {Number} The comparison value
20757 asInt : function(s) {
20758 var val = parseInt(String(s).replace(/,/g, ""));
20759 if(isNaN(val)) val = 0;
20764 * Ext JS Library 1.1.1
20765 * Copyright(c) 2006-2007, Ext JS, LLC.
20767 * Originally Released Under LGPL - original licence link has changed is not relivant.
20770 * <script type="text/javascript">
20774 * @class Roo.data.Record
20775 * Instances of this class encapsulate both record <em>definition</em> information, and record
20776 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20777 * to access Records cached in an {@link Roo.data.Store} object.<br>
20779 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20780 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20783 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20785 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20786 * {@link #create}. The parameters are the same.
20787 * @param {Array} data An associative Array of data values keyed by the field name.
20788 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20789 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20790 * not specified an integer id is generated.
20792 Roo.data.Record = function(data, id){
20793 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20798 * Generate a constructor for a specific record layout.
20799 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20800 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20801 * Each field definition object may contain the following properties: <ul>
20802 * <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,
20803 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20804 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20805 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20806 * is being used, then this is a string containing the javascript expression to reference the data relative to
20807 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20808 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20809 * this may be omitted.</p></li>
20810 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20811 * <ul><li>auto (Default, implies no conversion)</li>
20816 * <li>date</li></ul></p></li>
20817 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20818 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20819 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20820 * by the Reader into an object that will be stored in the Record. It is passed the
20821 * following parameters:<ul>
20822 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20824 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20826 * <br>usage:<br><pre><code>
20827 var TopicRecord = Roo.data.Record.create(
20828 {name: 'title', mapping: 'topic_title'},
20829 {name: 'author', mapping: 'username'},
20830 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20831 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20832 {name: 'lastPoster', mapping: 'user2'},
20833 {name: 'excerpt', mapping: 'post_text'}
20836 var myNewRecord = new TopicRecord({
20837 title: 'Do my job please',
20840 lastPost: new Date(),
20841 lastPoster: 'Animal',
20842 excerpt: 'No way dude!'
20844 myStore.add(myNewRecord);
20849 Roo.data.Record.create = function(o){
20850 var f = function(){
20851 f.superclass.constructor.apply(this, arguments);
20853 Roo.extend(f, Roo.data.Record);
20854 var p = f.prototype;
20855 p.fields = new Roo.util.MixedCollection(false, function(field){
20858 for(var i = 0, len = o.length; i < len; i++){
20859 p.fields.add(new Roo.data.Field(o[i]));
20861 f.getField = function(name){
20862 return p.fields.get(name);
20867 Roo.data.Record.AUTO_ID = 1000;
20868 Roo.data.Record.EDIT = 'edit';
20869 Roo.data.Record.REJECT = 'reject';
20870 Roo.data.Record.COMMIT = 'commit';
20872 Roo.data.Record.prototype = {
20874 * Readonly flag - true if this record has been modified.
20883 join : function(store){
20884 this.store = store;
20888 * Set the named field to the specified value.
20889 * @param {String} name The name of the field to set.
20890 * @param {Object} value The value to set the field to.
20892 set : function(name, value){
20893 if(this.data[name] == value){
20897 if(!this.modified){
20898 this.modified = {};
20900 if(typeof this.modified[name] == 'undefined'){
20901 this.modified[name] = this.data[name];
20903 this.data[name] = value;
20904 if(!this.editing && this.store){
20905 this.store.afterEdit(this);
20910 * Get the value of the named field.
20911 * @param {String} name The name of the field to get the value of.
20912 * @return {Object} The value of the field.
20914 get : function(name){
20915 return this.data[name];
20919 beginEdit : function(){
20920 this.editing = true;
20921 this.modified = {};
20925 cancelEdit : function(){
20926 this.editing = false;
20927 delete this.modified;
20931 endEdit : function(){
20932 this.editing = false;
20933 if(this.dirty && this.store){
20934 this.store.afterEdit(this);
20939 * Usually called by the {@link Roo.data.Store} which owns the Record.
20940 * Rejects all changes made to the Record since either creation, or the last commit operation.
20941 * Modified fields are reverted to their original values.
20943 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20944 * of reject operations.
20946 reject : function(){
20947 var m = this.modified;
20949 if(typeof m[n] != "function"){
20950 this.data[n] = m[n];
20953 this.dirty = false;
20954 delete this.modified;
20955 this.editing = false;
20957 this.store.afterReject(this);
20962 * Usually called by the {@link Roo.data.Store} which owns the Record.
20963 * Commits all changes made to the Record since either creation, or the last commit operation.
20965 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20966 * of commit operations.
20968 commit : function(){
20969 this.dirty = false;
20970 delete this.modified;
20971 this.editing = false;
20973 this.store.afterCommit(this);
20978 hasError : function(){
20979 return this.error != null;
20983 clearError : function(){
20988 * Creates a copy of this record.
20989 * @param {String} id (optional) A new record id if you don't want to use this record's id
20992 copy : function(newId) {
20993 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
20997 * Ext JS Library 1.1.1
20998 * Copyright(c) 2006-2007, Ext JS, LLC.
21000 * Originally Released Under LGPL - original licence link has changed is not relivant.
21003 * <script type="text/javascript">
21009 * @class Roo.data.Store
21010 * @extends Roo.util.Observable
21011 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21012 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21014 * 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
21015 * has no knowledge of the format of the data returned by the Proxy.<br>
21017 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21018 * instances from the data object. These records are cached and made available through accessor functions.
21020 * Creates a new Store.
21021 * @param {Object} config A config object containing the objects needed for the Store to access data,
21022 * and read the data into Records.
21024 Roo.data.Store = function(config){
21025 this.data = new Roo.util.MixedCollection(false);
21026 this.data.getKey = function(o){
21029 this.baseParams = {};
21031 this.paramNames = {
21036 "multisort" : "_multisort"
21039 if(config && config.data){
21040 this.inlineData = config.data;
21041 delete config.data;
21044 Roo.apply(this, config);
21046 if(this.reader){ // reader passed
21047 this.reader = Roo.factory(this.reader, Roo.data);
21048 this.reader.xmodule = this.xmodule || false;
21049 if(!this.recordType){
21050 this.recordType = this.reader.recordType;
21052 if(this.reader.onMetaChange){
21053 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21057 if(this.recordType){
21058 this.fields = this.recordType.prototype.fields;
21060 this.modified = [];
21064 * @event datachanged
21065 * Fires when the data cache has changed, and a widget which is using this Store
21066 * as a Record cache should refresh its view.
21067 * @param {Store} this
21069 datachanged : true,
21071 * @event metachange
21072 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21073 * @param {Store} this
21074 * @param {Object} meta The JSON metadata
21079 * Fires when Records have been added to the Store
21080 * @param {Store} this
21081 * @param {Roo.data.Record[]} records The array of Records added
21082 * @param {Number} index The index at which the record(s) were added
21087 * Fires when a Record has been removed from the Store
21088 * @param {Store} this
21089 * @param {Roo.data.Record} record The Record that was removed
21090 * @param {Number} index The index at which the record was removed
21095 * Fires when a Record has been updated
21096 * @param {Store} this
21097 * @param {Roo.data.Record} record The Record that was updated
21098 * @param {String} operation The update operation being performed. Value may be one of:
21100 Roo.data.Record.EDIT
21101 Roo.data.Record.REJECT
21102 Roo.data.Record.COMMIT
21108 * Fires when the data cache has been cleared.
21109 * @param {Store} this
21113 * @event beforeload
21114 * Fires before a request is made for a new data object. If the beforeload handler returns false
21115 * the load action will be canceled.
21116 * @param {Store} this
21117 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21121 * @event beforeloadadd
21122 * Fires after a new set of Records has been loaded.
21123 * @param {Store} this
21124 * @param {Roo.data.Record[]} records The Records that were loaded
21125 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21127 beforeloadadd : true,
21130 * Fires after a new set of Records has been loaded, before they are added to the store.
21131 * @param {Store} this
21132 * @param {Roo.data.Record[]} records The Records that were loaded
21133 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21134 * @params {Object} return from reader
21138 * @event loadexception
21139 * Fires if an exception occurs in the Proxy during loading.
21140 * Called with the signature of the Proxy's "loadexception" event.
21141 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21144 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21145 * @param {Object} load options
21146 * @param {Object} jsonData from your request (normally this contains the Exception)
21148 loadexception : true
21152 this.proxy = Roo.factory(this.proxy, Roo.data);
21153 this.proxy.xmodule = this.xmodule || false;
21154 this.relayEvents(this.proxy, ["loadexception"]);
21156 this.sortToggle = {};
21157 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21159 Roo.data.Store.superclass.constructor.call(this);
21161 if(this.inlineData){
21162 this.loadData(this.inlineData);
21163 delete this.inlineData;
21167 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21169 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21170 * without a remote query - used by combo/forms at present.
21174 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21177 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21180 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21181 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21184 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21185 * on any HTTP request
21188 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21191 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21195 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21196 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21198 remoteSort : false,
21201 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21202 * loaded or when a record is removed. (defaults to false).
21204 pruneModifiedRecords : false,
21207 lastOptions : null,
21210 * Add Records to the Store and fires the add event.
21211 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21213 add : function(records){
21214 records = [].concat(records);
21215 for(var i = 0, len = records.length; i < len; i++){
21216 records[i].join(this);
21218 var index = this.data.length;
21219 this.data.addAll(records);
21220 this.fireEvent("add", this, records, index);
21224 * Remove a Record from the Store and fires the remove event.
21225 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21227 remove : function(record){
21228 var index = this.data.indexOf(record);
21229 this.data.removeAt(index);
21230 if(this.pruneModifiedRecords){
21231 this.modified.remove(record);
21233 this.fireEvent("remove", this, record, index);
21237 * Remove all Records from the Store and fires the clear event.
21239 removeAll : function(){
21241 if(this.pruneModifiedRecords){
21242 this.modified = [];
21244 this.fireEvent("clear", this);
21248 * Inserts Records to the Store at the given index and fires the add event.
21249 * @param {Number} index The start index at which to insert the passed Records.
21250 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21252 insert : function(index, records){
21253 records = [].concat(records);
21254 for(var i = 0, len = records.length; i < len; i++){
21255 this.data.insert(index, records[i]);
21256 records[i].join(this);
21258 this.fireEvent("add", this, records, index);
21262 * Get the index within the cache of the passed Record.
21263 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21264 * @return {Number} The index of the passed Record. Returns -1 if not found.
21266 indexOf : function(record){
21267 return this.data.indexOf(record);
21271 * Get the index within the cache of the Record with the passed id.
21272 * @param {String} id The id of the Record to find.
21273 * @return {Number} The index of the Record. Returns -1 if not found.
21275 indexOfId : function(id){
21276 return this.data.indexOfKey(id);
21280 * Get the Record with the specified id.
21281 * @param {String} id The id of the Record to find.
21282 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21284 getById : function(id){
21285 return this.data.key(id);
21289 * Get the Record at the specified index.
21290 * @param {Number} index The index of the Record to find.
21291 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21293 getAt : function(index){
21294 return this.data.itemAt(index);
21298 * Returns a range of Records between specified indices.
21299 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21300 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21301 * @return {Roo.data.Record[]} An array of Records
21303 getRange : function(start, end){
21304 return this.data.getRange(start, end);
21308 storeOptions : function(o){
21309 o = Roo.apply({}, o);
21312 this.lastOptions = o;
21316 * Loads the Record cache from the configured Proxy using the configured Reader.
21318 * If using remote paging, then the first load call must specify the <em>start</em>
21319 * and <em>limit</em> properties in the options.params property to establish the initial
21320 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21322 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21323 * and this call will return before the new data has been loaded. Perform any post-processing
21324 * in a callback function, or in a "load" event handler.</strong>
21326 * @param {Object} options An object containing properties which control loading options:<ul>
21327 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21328 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21329 * passed the following arguments:<ul>
21330 * <li>r : Roo.data.Record[]</li>
21331 * <li>options: Options object from the load call</li>
21332 * <li>success: Boolean success indicator</li></ul></li>
21333 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21334 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21337 load : function(options){
21338 options = options || {};
21339 if(this.fireEvent("beforeload", this, options) !== false){
21340 this.storeOptions(options);
21341 var p = Roo.apply(options.params || {}, this.baseParams);
21342 // if meta was not loaded from remote source.. try requesting it.
21343 if (!this.reader.metaFromRemote) {
21344 p._requestMeta = 1;
21346 if(this.sortInfo && this.remoteSort){
21347 var pn = this.paramNames;
21348 p[pn["sort"]] = this.sortInfo.field;
21349 p[pn["dir"]] = this.sortInfo.direction;
21351 if (this.multiSort) {
21352 var pn = this.paramNames;
21353 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21356 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21361 * Reloads the Record cache from the configured Proxy using the configured Reader and
21362 * the options from the last load operation performed.
21363 * @param {Object} options (optional) An object containing properties which may override the options
21364 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21365 * the most recently used options are reused).
21367 reload : function(options){
21368 this.load(Roo.applyIf(options||{}, this.lastOptions));
21372 // Called as a callback by the Reader during a load operation.
21373 loadRecords : function(o, options, success){
21374 if(!o || success === false){
21375 if(success !== false){
21376 this.fireEvent("load", this, [], options, o);
21378 if(options.callback){
21379 options.callback.call(options.scope || this, [], options, false);
21383 // if data returned failure - throw an exception.
21384 if (o.success === false) {
21385 // show a message if no listener is registered.
21386 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21387 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21389 // loadmask wil be hooked into this..
21390 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21393 var r = o.records, t = o.totalRecords || r.length;
21395 this.fireEvent("beforeloadadd", this, r, options, o);
21397 if(!options || options.add !== true){
21398 if(this.pruneModifiedRecords){
21399 this.modified = [];
21401 for(var i = 0, len = r.length; i < len; i++){
21405 this.data = this.snapshot;
21406 delete this.snapshot;
21409 this.data.addAll(r);
21410 this.totalLength = t;
21412 this.fireEvent("datachanged", this);
21414 this.totalLength = Math.max(t, this.data.length+r.length);
21417 this.fireEvent("load", this, r, options, o);
21418 if(options.callback){
21419 options.callback.call(options.scope || this, r, options, true);
21425 * Loads data from a passed data block. A Reader which understands the format of the data
21426 * must have been configured in the constructor.
21427 * @param {Object} data The data block from which to read the Records. The format of the data expected
21428 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21429 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21431 loadData : function(o, append){
21432 var r = this.reader.readRecords(o);
21433 this.loadRecords(r, {add: append}, true);
21437 * Gets the number of cached records.
21439 * <em>If using paging, this may not be the total size of the dataset. If the data object
21440 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21441 * the data set size</em>
21443 getCount : function(){
21444 return this.data.length || 0;
21448 * Gets the total number of records in the dataset as returned by the server.
21450 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21451 * the dataset size</em>
21453 getTotalCount : function(){
21454 return this.totalLength || 0;
21458 * Returns the sort state of the Store as an object with two properties:
21460 field {String} The name of the field by which the Records are sorted
21461 direction {String} The sort order, "ASC" or "DESC"
21464 getSortState : function(){
21465 return this.sortInfo;
21469 applySort : function(){
21470 if(this.sortInfo && !this.remoteSort){
21471 var s = this.sortInfo, f = s.field;
21472 var st = this.fields.get(f).sortType;
21473 var fn = function(r1, r2){
21474 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21475 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21477 this.data.sort(s.direction, fn);
21478 if(this.snapshot && this.snapshot != this.data){
21479 this.snapshot.sort(s.direction, fn);
21485 * Sets the default sort column and order to be used by the next load operation.
21486 * @param {String} fieldName The name of the field to sort by.
21487 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21489 setDefaultSort : function(field, dir){
21490 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21494 * Sort the Records.
21495 * If remote sorting is used, the sort is performed on the server, and the cache is
21496 * reloaded. If local sorting is used, the cache is sorted internally.
21497 * @param {String} fieldName The name of the field to sort by.
21498 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21500 sort : function(fieldName, dir){
21501 var f = this.fields.get(fieldName);
21503 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21505 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21506 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21511 this.sortToggle[f.name] = dir;
21512 this.sortInfo = {field: f.name, direction: dir};
21513 if(!this.remoteSort){
21515 this.fireEvent("datachanged", this);
21517 this.load(this.lastOptions);
21522 * Calls the specified function for each of the Records in the cache.
21523 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21524 * Returning <em>false</em> aborts and exits the iteration.
21525 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21527 each : function(fn, scope){
21528 this.data.each(fn, scope);
21532 * Gets all records modified since the last commit. Modified records are persisted across load operations
21533 * (e.g., during paging).
21534 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21536 getModifiedRecords : function(){
21537 return this.modified;
21541 createFilterFn : function(property, value, anyMatch){
21542 if(!value.exec){ // not a regex
21543 value = String(value);
21544 if(value.length == 0){
21547 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21549 return function(r){
21550 return value.test(r.data[property]);
21555 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21556 * @param {String} property A field on your records
21557 * @param {Number} start The record index to start at (defaults to 0)
21558 * @param {Number} end The last record index to include (defaults to length - 1)
21559 * @return {Number} The sum
21561 sum : function(property, start, end){
21562 var rs = this.data.items, v = 0;
21563 start = start || 0;
21564 end = (end || end === 0) ? end : rs.length-1;
21566 for(var i = start; i <= end; i++){
21567 v += (rs[i].data[property] || 0);
21573 * Filter the records by a specified property.
21574 * @param {String} field A field on your records
21575 * @param {String/RegExp} value Either a string that the field
21576 * should start with or a RegExp to test against the field
21577 * @param {Boolean} anyMatch True to match any part not just the beginning
21579 filter : function(property, value, anyMatch){
21580 var fn = this.createFilterFn(property, value, anyMatch);
21581 return fn ? this.filterBy(fn) : this.clearFilter();
21585 * Filter by a function. The specified function will be called with each
21586 * record in this data source. If the function returns true the record is included,
21587 * otherwise it is filtered.
21588 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21589 * @param {Object} scope (optional) The scope of the function (defaults to this)
21591 filterBy : function(fn, scope){
21592 this.snapshot = this.snapshot || this.data;
21593 this.data = this.queryBy(fn, scope||this);
21594 this.fireEvent("datachanged", this);
21598 * Query the records by a specified property.
21599 * @param {String} field A field on your records
21600 * @param {String/RegExp} value Either a string that the field
21601 * should start with or a RegExp to test against the field
21602 * @param {Boolean} anyMatch True to match any part not just the beginning
21603 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21605 query : function(property, value, anyMatch){
21606 var fn = this.createFilterFn(property, value, anyMatch);
21607 return fn ? this.queryBy(fn) : this.data.clone();
21611 * Query by a function. The specified function will be called with each
21612 * record in this data source. If the function returns true the record is included
21614 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21615 * @param {Object} scope (optional) The scope of the function (defaults to this)
21616 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21618 queryBy : function(fn, scope){
21619 var data = this.snapshot || this.data;
21620 return data.filterBy(fn, scope||this);
21624 * Collects unique values for a particular dataIndex from this store.
21625 * @param {String} dataIndex The property to collect
21626 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21627 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21628 * @return {Array} An array of the unique values
21630 collect : function(dataIndex, allowNull, bypassFilter){
21631 var d = (bypassFilter === true && this.snapshot) ?
21632 this.snapshot.items : this.data.items;
21633 var v, sv, r = [], l = {};
21634 for(var i = 0, len = d.length; i < len; i++){
21635 v = d[i].data[dataIndex];
21637 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21646 * Revert to a view of the Record cache with no filtering applied.
21647 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21649 clearFilter : function(suppressEvent){
21650 if(this.snapshot && this.snapshot != this.data){
21651 this.data = this.snapshot;
21652 delete this.snapshot;
21653 if(suppressEvent !== true){
21654 this.fireEvent("datachanged", this);
21660 afterEdit : function(record){
21661 if(this.modified.indexOf(record) == -1){
21662 this.modified.push(record);
21664 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21668 afterReject : function(record){
21669 this.modified.remove(record);
21670 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21674 afterCommit : function(record){
21675 this.modified.remove(record);
21676 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21680 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21681 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21683 commitChanges : function(){
21684 var m = this.modified.slice(0);
21685 this.modified = [];
21686 for(var i = 0, len = m.length; i < len; i++){
21692 * Cancel outstanding changes on all changed records.
21694 rejectChanges : function(){
21695 var m = this.modified.slice(0);
21696 this.modified = [];
21697 for(var i = 0, len = m.length; i < len; i++){
21702 onMetaChange : function(meta, rtype, o){
21703 this.recordType = rtype;
21704 this.fields = rtype.prototype.fields;
21705 delete this.snapshot;
21706 this.sortInfo = meta.sortInfo || this.sortInfo;
21707 this.modified = [];
21708 this.fireEvent('metachange', this, this.reader.meta);
21712 * Ext JS Library 1.1.1
21713 * Copyright(c) 2006-2007, Ext JS, LLC.
21715 * Originally Released Under LGPL - original licence link has changed is not relivant.
21718 * <script type="text/javascript">
21722 * @class Roo.data.SimpleStore
21723 * @extends Roo.data.Store
21724 * Small helper class to make creating Stores from Array data easier.
21725 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21726 * @cfg {Array} fields An array of field definition objects, or field name strings.
21727 * @cfg {Array} data The multi-dimensional array of data
21729 * @param {Object} config
21731 Roo.data.SimpleStore = function(config){
21732 Roo.data.SimpleStore.superclass.constructor.call(this, {
21734 reader: new Roo.data.ArrayReader({
21737 Roo.data.Record.create(config.fields)
21739 proxy : new Roo.data.MemoryProxy(config.data)
21743 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21745 * Ext JS Library 1.1.1
21746 * Copyright(c) 2006-2007, Ext JS, LLC.
21748 * Originally Released Under LGPL - original licence link has changed is not relivant.
21751 * <script type="text/javascript">
21756 * @extends Roo.data.Store
21757 * @class Roo.data.JsonStore
21758 * Small helper class to make creating Stores for JSON data easier. <br/>
21760 var store = new Roo.data.JsonStore({
21761 url: 'get-images.php',
21763 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21766 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21767 * JsonReader and HttpProxy (unless inline data is provided).</b>
21768 * @cfg {Array} fields An array of field definition objects, or field name strings.
21770 * @param {Object} config
21772 Roo.data.JsonStore = function(c){
21773 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21774 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21775 reader: new Roo.data.JsonReader(c, c.fields)
21778 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21780 * Ext JS Library 1.1.1
21781 * Copyright(c) 2006-2007, Ext JS, LLC.
21783 * Originally Released Under LGPL - original licence link has changed is not relivant.
21786 * <script type="text/javascript">
21790 Roo.data.Field = function(config){
21791 if(typeof config == "string"){
21792 config = {name: config};
21794 Roo.apply(this, config);
21797 this.type = "auto";
21800 var st = Roo.data.SortTypes;
21801 // named sortTypes are supported, here we look them up
21802 if(typeof this.sortType == "string"){
21803 this.sortType = st[this.sortType];
21806 // set default sortType for strings and dates
21807 if(!this.sortType){
21810 this.sortType = st.asUCString;
21813 this.sortType = st.asDate;
21816 this.sortType = st.none;
21821 var stripRe = /[\$,%]/g;
21823 // prebuilt conversion function for this field, instead of
21824 // switching every time we're reading a value
21826 var cv, dateFormat = this.dateFormat;
21831 cv = function(v){ return v; };
21834 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
21838 return v !== undefined && v !== null && v !== '' ?
21839 parseInt(String(v).replace(stripRe, ""), 10) : '';
21844 return v !== undefined && v !== null && v !== '' ?
21845 parseFloat(String(v).replace(stripRe, ""), 10) : '';
21850 cv = function(v){ return v === true || v === "true" || v == 1; };
21857 if(v instanceof Date){
21861 if(dateFormat == "timestamp"){
21862 return new Date(v*1000);
21864 return Date.parseDate(v, dateFormat);
21866 var parsed = Date.parse(v);
21867 return parsed ? new Date(parsed) : null;
21876 Roo.data.Field.prototype = {
21884 * Ext JS Library 1.1.1
21885 * Copyright(c) 2006-2007, Ext JS, LLC.
21887 * Originally Released Under LGPL - original licence link has changed is not relivant.
21890 * <script type="text/javascript">
21893 // Base class for reading structured data from a data source. This class is intended to be
21894 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
21897 * @class Roo.data.DataReader
21898 * Base class for reading structured data from a data source. This class is intended to be
21899 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
21902 Roo.data.DataReader = function(meta, recordType){
21906 this.recordType = recordType instanceof Array ?
21907 Roo.data.Record.create(recordType) : recordType;
21910 Roo.data.DataReader.prototype = {
21912 * Create an empty record
21913 * @param {Object} data (optional) - overlay some values
21914 * @return {Roo.data.Record} record created.
21916 newRow : function(d) {
21918 this.recordType.prototype.fields.each(function(c) {
21920 case 'int' : da[c.name] = 0; break;
21921 case 'date' : da[c.name] = new Date(); break;
21922 case 'float' : da[c.name] = 0.0; break;
21923 case 'boolean' : da[c.name] = false; break;
21924 default : da[c.name] = ""; break;
21928 return new this.recordType(Roo.apply(da, d));
21933 * Ext JS Library 1.1.1
21934 * Copyright(c) 2006-2007, Ext JS, LLC.
21936 * Originally Released Under LGPL - original licence link has changed is not relivant.
21939 * <script type="text/javascript">
21943 * @class Roo.data.DataProxy
21944 * @extends Roo.data.Observable
21945 * This class is an abstract base class for implementations which provide retrieval of
21946 * unformatted data objects.<br>
21948 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
21949 * (of the appropriate type which knows how to parse the data object) to provide a block of
21950 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
21952 * Custom implementations must implement the load method as described in
21953 * {@link Roo.data.HttpProxy#load}.
21955 Roo.data.DataProxy = function(){
21958 * @event beforeload
21959 * Fires before a network request is made to retrieve a data object.
21960 * @param {Object} This DataProxy object.
21961 * @param {Object} params The params parameter to the load function.
21966 * Fires before the load method's callback is called.
21967 * @param {Object} This DataProxy object.
21968 * @param {Object} o The data object.
21969 * @param {Object} arg The callback argument object passed to the load function.
21973 * @event loadexception
21974 * Fires if an Exception occurs during data retrieval.
21975 * @param {Object} This DataProxy object.
21976 * @param {Object} o The data object.
21977 * @param {Object} arg The callback argument object passed to the load function.
21978 * @param {Object} e The Exception.
21980 loadexception : true
21982 Roo.data.DataProxy.superclass.constructor.call(this);
21985 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
21988 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
21992 * Ext JS Library 1.1.1
21993 * Copyright(c) 2006-2007, Ext JS, LLC.
21995 * Originally Released Under LGPL - original licence link has changed is not relivant.
21998 * <script type="text/javascript">
22001 * @class Roo.data.MemoryProxy
22002 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22003 * to the Reader when its load method is called.
22005 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22007 Roo.data.MemoryProxy = function(data){
22011 Roo.data.MemoryProxy.superclass.constructor.call(this);
22015 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22017 * Load data from the requested source (in this case an in-memory
22018 * data object passed to the constructor), read the data object into
22019 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22020 * process that block using the passed callback.
22021 * @param {Object} params This parameter is not used by the MemoryProxy class.
22022 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22023 * object into a block of Roo.data.Records.
22024 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22025 * The function must be passed <ul>
22026 * <li>The Record block object</li>
22027 * <li>The "arg" argument from the load function</li>
22028 * <li>A boolean success indicator</li>
22030 * @param {Object} scope The scope in which to call the callback
22031 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22033 load : function(params, reader, callback, scope, arg){
22034 params = params || {};
22037 result = reader.readRecords(this.data);
22039 this.fireEvent("loadexception", this, arg, null, e);
22040 callback.call(scope, null, arg, false);
22043 callback.call(scope, result, arg, true);
22047 update : function(params, records){
22052 * Ext JS Library 1.1.1
22053 * Copyright(c) 2006-2007, Ext JS, LLC.
22055 * Originally Released Under LGPL - original licence link has changed is not relivant.
22058 * <script type="text/javascript">
22061 * @class Roo.data.HttpProxy
22062 * @extends Roo.data.DataProxy
22063 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22064 * configured to reference a certain URL.<br><br>
22066 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22067 * from which the running page was served.<br><br>
22069 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22071 * Be aware that to enable the browser to parse an XML document, the server must set
22072 * the Content-Type header in the HTTP response to "text/xml".
22074 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22075 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22076 * will be used to make the request.
22078 Roo.data.HttpProxy = function(conn){
22079 Roo.data.HttpProxy.superclass.constructor.call(this);
22080 // is conn a conn config or a real conn?
22082 this.useAjax = !conn || !conn.events;
22086 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22087 // thse are take from connection...
22090 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22093 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22094 * extra parameters to each request made by this object. (defaults to undefined)
22097 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22098 * to each request made by this object. (defaults to undefined)
22101 * @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)
22104 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22107 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22113 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22117 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22118 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22119 * a finer-grained basis than the DataProxy events.
22121 getConnection : function(){
22122 return this.useAjax ? Roo.Ajax : this.conn;
22126 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22127 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22128 * process that block using the passed callback.
22129 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22130 * for the request to the remote server.
22131 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22132 * object into a block of Roo.data.Records.
22133 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22134 * The function must be passed <ul>
22135 * <li>The Record block object</li>
22136 * <li>The "arg" argument from the load function</li>
22137 * <li>A boolean success indicator</li>
22139 * @param {Object} scope The scope in which to call the callback
22140 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22142 load : function(params, reader, callback, scope, arg){
22143 if(this.fireEvent("beforeload", this, params) !== false){
22145 params : params || {},
22147 callback : callback,
22152 callback : this.loadResponse,
22156 Roo.applyIf(o, this.conn);
22157 if(this.activeRequest){
22158 Roo.Ajax.abort(this.activeRequest);
22160 this.activeRequest = Roo.Ajax.request(o);
22162 this.conn.request(o);
22165 callback.call(scope||this, null, arg, false);
22170 loadResponse : function(o, success, response){
22171 delete this.activeRequest;
22173 this.fireEvent("loadexception", this, o, response);
22174 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22179 result = o.reader.read(response);
22181 this.fireEvent("loadexception", this, o, response, e);
22182 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22186 this.fireEvent("load", this, o, o.request.arg);
22187 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22191 update : function(dataSet){
22196 updateResponse : function(dataSet){
22201 * Ext JS Library 1.1.1
22202 * Copyright(c) 2006-2007, Ext JS, LLC.
22204 * Originally Released Under LGPL - original licence link has changed is not relivant.
22207 * <script type="text/javascript">
22211 * @class Roo.data.ScriptTagProxy
22212 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22213 * other than the originating domain of the running page.<br><br>
22215 * <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
22216 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22218 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22219 * source code that is used as the source inside a <script> tag.<br><br>
22221 * In order for the browser to process the returned data, the server must wrap the data object
22222 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22223 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22224 * depending on whether the callback name was passed:
22227 boolean scriptTag = false;
22228 String cb = request.getParameter("callback");
22231 response.setContentType("text/javascript");
22233 response.setContentType("application/x-json");
22235 Writer out = response.getWriter();
22237 out.write(cb + "(");
22239 out.print(dataBlock.toJsonString());
22246 * @param {Object} config A configuration object.
22248 Roo.data.ScriptTagProxy = function(config){
22249 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22250 Roo.apply(this, config);
22251 this.head = document.getElementsByTagName("head")[0];
22254 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22256 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22258 * @cfg {String} url The URL from which to request the data object.
22261 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22265 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22266 * the server the name of the callback function set up by the load call to process the returned data object.
22267 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22268 * javascript output which calls this named function passing the data object as its only parameter.
22270 callbackParam : "callback",
22272 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22273 * name to the request.
22278 * Load data from the configured URL, read the data object into
22279 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22280 * process that block using the passed callback.
22281 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22282 * for the request to the remote server.
22283 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22284 * object into a block of Roo.data.Records.
22285 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22286 * The function must be passed <ul>
22287 * <li>The Record block object</li>
22288 * <li>The "arg" argument from the load function</li>
22289 * <li>A boolean success indicator</li>
22291 * @param {Object} scope The scope in which to call the callback
22292 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22294 load : function(params, reader, callback, scope, arg){
22295 if(this.fireEvent("beforeload", this, params) !== false){
22297 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22299 var url = this.url;
22300 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22302 url += "&_dc=" + (new Date().getTime());
22304 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22307 cb : "stcCallback"+transId,
22308 scriptId : "stcScript"+transId,
22312 callback : callback,
22318 window[trans.cb] = function(o){
22319 conn.handleResponse(o, trans);
22322 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22324 if(this.autoAbort !== false){
22328 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22330 var script = document.createElement("script");
22331 script.setAttribute("src", url);
22332 script.setAttribute("type", "text/javascript");
22333 script.setAttribute("id", trans.scriptId);
22334 this.head.appendChild(script);
22336 this.trans = trans;
22338 callback.call(scope||this, null, arg, false);
22343 isLoading : function(){
22344 return this.trans ? true : false;
22348 * Abort the current server request.
22350 abort : function(){
22351 if(this.isLoading()){
22352 this.destroyTrans(this.trans);
22357 destroyTrans : function(trans, isLoaded){
22358 this.head.removeChild(document.getElementById(trans.scriptId));
22359 clearTimeout(trans.timeoutId);
22361 window[trans.cb] = undefined;
22363 delete window[trans.cb];
22366 // if hasn't been loaded, wait for load to remove it to prevent script error
22367 window[trans.cb] = function(){
22368 window[trans.cb] = undefined;
22370 delete window[trans.cb];
22377 handleResponse : function(o, trans){
22378 this.trans = false;
22379 this.destroyTrans(trans, true);
22382 result = trans.reader.readRecords(o);
22384 this.fireEvent("loadexception", this, o, trans.arg, e);
22385 trans.callback.call(trans.scope||window, null, trans.arg, false);
22388 this.fireEvent("load", this, o, trans.arg);
22389 trans.callback.call(trans.scope||window, result, trans.arg, true);
22393 handleFailure : function(trans){
22394 this.trans = false;
22395 this.destroyTrans(trans, false);
22396 this.fireEvent("loadexception", this, null, trans.arg);
22397 trans.callback.call(trans.scope||window, null, trans.arg, false);
22401 * Ext JS Library 1.1.1
22402 * Copyright(c) 2006-2007, Ext JS, LLC.
22404 * Originally Released Under LGPL - original licence link has changed is not relivant.
22407 * <script type="text/javascript">
22411 * @class Roo.data.JsonReader
22412 * @extends Roo.data.DataReader
22413 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22414 * based on mappings in a provided Roo.data.Record constructor.
22416 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22417 * in the reply previously.
22422 var RecordDef = Roo.data.Record.create([
22423 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22424 {name: 'occupation'} // This field will use "occupation" as the mapping.
22426 var myReader = new Roo.data.JsonReader({
22427 totalProperty: "results", // The property which contains the total dataset size (optional)
22428 root: "rows", // The property which contains an Array of row objects
22429 id: "id" // The property within each row object that provides an ID for the record (optional)
22433 * This would consume a JSON file like this:
22435 { 'results': 2, 'rows': [
22436 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22437 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22440 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22441 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22442 * paged from the remote server.
22443 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22444 * @cfg {String} root name of the property which contains the Array of row objects.
22445 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22447 * Create a new JsonReader
22448 * @param {Object} meta Metadata configuration options
22449 * @param {Object} recordType Either an Array of field definition objects,
22450 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22452 Roo.data.JsonReader = function(meta, recordType){
22455 // set some defaults:
22456 Roo.applyIf(meta, {
22457 totalProperty: 'total',
22458 successProperty : 'success',
22463 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22465 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22468 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22469 * Used by Store query builder to append _requestMeta to params.
22472 metaFromRemote : false,
22474 * This method is only used by a DataProxy which has retrieved data from a remote server.
22475 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22476 * @return {Object} data A data block which is used by an Roo.data.Store object as
22477 * a cache of Roo.data.Records.
22479 read : function(response){
22480 var json = response.responseText;
22482 var o = /* eval:var:o */ eval("("+json+")");
22484 throw {message: "JsonReader.read: Json object not found"};
22490 this.metaFromRemote = true;
22491 this.meta = o.metaData;
22492 this.recordType = Roo.data.Record.create(o.metaData.fields);
22493 this.onMetaChange(this.meta, this.recordType, o);
22495 return this.readRecords(o);
22498 // private function a store will implement
22499 onMetaChange : function(meta, recordType, o){
22506 simpleAccess: function(obj, subsc) {
22513 getJsonAccessor: function(){
22515 return function(expr) {
22517 return(re.test(expr))
22518 ? new Function("obj", "return obj." + expr)
22523 return Roo.emptyFn;
22528 * Create a data block containing Roo.data.Records from an XML document.
22529 * @param {Object} o An object which contains an Array of row objects in the property specified
22530 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22531 * which contains the total size of the dataset.
22532 * @return {Object} data A data block which is used by an Roo.data.Store object as
22533 * a cache of Roo.data.Records.
22535 readRecords : function(o){
22537 * After any data loads, the raw JSON data is available for further custom processing.
22541 var s = this.meta, Record = this.recordType,
22542 f = Record.prototype.fields, fi = f.items, fl = f.length;
22544 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22546 if(s.totalProperty) {
22547 this.getTotal = this.getJsonAccessor(s.totalProperty);
22549 if(s.successProperty) {
22550 this.getSuccess = this.getJsonAccessor(s.successProperty);
22552 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22554 var g = this.getJsonAccessor(s.id);
22555 this.getId = function(rec) {
22557 return (r === undefined || r === "") ? null : r;
22560 this.getId = function(){return null;};
22563 for(var jj = 0; jj < fl; jj++){
22565 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22566 this.ef[jj] = this.getJsonAccessor(map);
22570 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22571 if(s.totalProperty){
22572 var vt = parseInt(this.getTotal(o), 10);
22577 if(s.successProperty){
22578 var vs = this.getSuccess(o);
22579 if(vs === false || vs === 'false'){
22584 for(var i = 0; i < c; i++){
22587 var id = this.getId(n);
22588 for(var j = 0; j < fl; j++){
22590 var v = this.ef[j](n);
22592 Roo.log('missing convert for ' + f.name);
22596 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22598 var record = new Record(values, id);
22600 records[i] = record;
22606 totalRecords : totalRecords
22611 * Ext JS Library 1.1.1
22612 * Copyright(c) 2006-2007, Ext JS, LLC.
22614 * Originally Released Under LGPL - original licence link has changed is not relivant.
22617 * <script type="text/javascript">
22621 * @class Roo.data.XmlReader
22622 * @extends Roo.data.DataReader
22623 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22624 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22626 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22627 * header in the HTTP response must be set to "text/xml".</em>
22631 var RecordDef = Roo.data.Record.create([
22632 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22633 {name: 'occupation'} // This field will use "occupation" as the mapping.
22635 var myReader = new Roo.data.XmlReader({
22636 totalRecords: "results", // The element which contains the total dataset size (optional)
22637 record: "row", // The repeated element which contains row information
22638 id: "id" // The element within the row that provides an ID for the record (optional)
22642 * This would consume an XML file like this:
22646 <results>2</results>
22649 <name>Bill</name>
22650 <occupation>Gardener</occupation>
22654 <name>Ben</name>
22655 <occupation>Horticulturalist</occupation>
22659 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22660 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22661 * paged from the remote server.
22662 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22663 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22664 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22665 * a record identifier value.
22667 * Create a new XmlReader
22668 * @param {Object} meta Metadata configuration options
22669 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22670 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22671 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22673 Roo.data.XmlReader = function(meta, recordType){
22675 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22677 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22679 * This method is only used by a DataProxy which has retrieved data from a remote server.
22680 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22681 * to contain a method called 'responseXML' that returns an XML document object.
22682 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22683 * a cache of Roo.data.Records.
22685 read : function(response){
22686 var doc = response.responseXML;
22688 throw {message: "XmlReader.read: XML Document not available"};
22690 return this.readRecords(doc);
22694 * Create a data block containing Roo.data.Records from an XML document.
22695 * @param {Object} doc A parsed XML document.
22696 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22697 * a cache of Roo.data.Records.
22699 readRecords : function(doc){
22701 * After any data loads/reads, the raw XML Document is available for further custom processing.
22702 * @type XMLDocument
22704 this.xmlData = doc;
22705 var root = doc.documentElement || doc;
22706 var q = Roo.DomQuery;
22707 var recordType = this.recordType, fields = recordType.prototype.fields;
22708 var sid = this.meta.id;
22709 var totalRecords = 0, success = true;
22710 if(this.meta.totalRecords){
22711 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22714 if(this.meta.success){
22715 var sv = q.selectValue(this.meta.success, root, true);
22716 success = sv !== false && sv !== 'false';
22719 var ns = q.select(this.meta.record, root);
22720 for(var i = 0, len = ns.length; i < len; i++) {
22723 var id = sid ? q.selectValue(sid, n) : undefined;
22724 for(var j = 0, jlen = fields.length; j < jlen; j++){
22725 var f = fields.items[j];
22726 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22728 values[f.name] = v;
22730 var record = new recordType(values, id);
22732 records[records.length] = record;
22738 totalRecords : totalRecords || records.length
22743 * Ext JS Library 1.1.1
22744 * Copyright(c) 2006-2007, Ext JS, LLC.
22746 * Originally Released Under LGPL - original licence link has changed is not relivant.
22749 * <script type="text/javascript">
22753 * @class Roo.data.ArrayReader
22754 * @extends Roo.data.DataReader
22755 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22756 * Each element of that Array represents a row of data fields. The
22757 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22758 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22762 var RecordDef = Roo.data.Record.create([
22763 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22764 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22766 var myReader = new Roo.data.ArrayReader({
22767 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22771 * This would consume an Array like this:
22773 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22775 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22777 * Create a new JsonReader
22778 * @param {Object} meta Metadata configuration options.
22779 * @param {Object} recordType Either an Array of field definition objects
22780 * as specified to {@link Roo.data.Record#create},
22781 * or an {@link Roo.data.Record} object
22782 * created using {@link Roo.data.Record#create}.
22784 Roo.data.ArrayReader = function(meta, recordType){
22785 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22788 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22790 * Create a data block containing Roo.data.Records from an XML document.
22791 * @param {Object} o An Array of row objects which represents the dataset.
22792 * @return {Object} data A data block which is used by an Roo.data.Store object as
22793 * a cache of Roo.data.Records.
22795 readRecords : function(o){
22796 var sid = this.meta ? this.meta.id : null;
22797 var recordType = this.recordType, fields = recordType.prototype.fields;
22800 for(var i = 0; i < root.length; i++){
22803 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22804 for(var j = 0, jlen = fields.length; j < jlen; j++){
22805 var f = fields.items[j];
22806 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22807 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22809 values[f.name] = v;
22811 var record = new recordType(values, id);
22813 records[records.length] = record;
22817 totalRecords : records.length
22822 * Ext JS Library 1.1.1
22823 * Copyright(c) 2006-2007, Ext JS, LLC.
22825 * Originally Released Under LGPL - original licence link has changed is not relivant.
22828 * <script type="text/javascript">
22833 * @class Roo.data.Tree
22834 * @extends Roo.util.Observable
22835 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
22836 * in the tree have most standard DOM functionality.
22838 * @param {Node} root (optional) The root node
22840 Roo.data.Tree = function(root){
22841 this.nodeHash = {};
22843 * The root node for this tree
22848 this.setRootNode(root);
22853 * Fires when a new child node is appended to a node in this tree.
22854 * @param {Tree} tree The owner tree
22855 * @param {Node} parent The parent node
22856 * @param {Node} node The newly appended node
22857 * @param {Number} index The index of the newly appended node
22862 * Fires when a child node is removed from a node in this tree.
22863 * @param {Tree} tree The owner tree
22864 * @param {Node} parent The parent node
22865 * @param {Node} node The child node removed
22870 * Fires when a node is moved to a new location in the tree
22871 * @param {Tree} tree The owner tree
22872 * @param {Node} node The node moved
22873 * @param {Node} oldParent The old parent of this node
22874 * @param {Node} newParent The new parent of this node
22875 * @param {Number} index The index it was moved to
22880 * Fires when a new child node is inserted in a node in this tree.
22881 * @param {Tree} tree The owner tree
22882 * @param {Node} parent The parent node
22883 * @param {Node} node The child node inserted
22884 * @param {Node} refNode The child node the node was inserted before
22888 * @event beforeappend
22889 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
22890 * @param {Tree} tree The owner tree
22891 * @param {Node} parent The parent node
22892 * @param {Node} node The child node to be appended
22894 "beforeappend" : true,
22896 * @event beforeremove
22897 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
22898 * @param {Tree} tree The owner tree
22899 * @param {Node} parent The parent node
22900 * @param {Node} node The child node to be removed
22902 "beforeremove" : true,
22904 * @event beforemove
22905 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
22906 * @param {Tree} tree The owner tree
22907 * @param {Node} node The node being moved
22908 * @param {Node} oldParent The parent of the node
22909 * @param {Node} newParent The new parent the node is moving to
22910 * @param {Number} index The index it is being moved to
22912 "beforemove" : true,
22914 * @event beforeinsert
22915 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
22916 * @param {Tree} tree The owner tree
22917 * @param {Node} parent The parent node
22918 * @param {Node} node The child node to be inserted
22919 * @param {Node} refNode The child node the node is being inserted before
22921 "beforeinsert" : true
22924 Roo.data.Tree.superclass.constructor.call(this);
22927 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
22928 pathSeparator: "/",
22930 proxyNodeEvent : function(){
22931 return this.fireEvent.apply(this, arguments);
22935 * Returns the root node for this tree.
22938 getRootNode : function(){
22943 * Sets the root node for this tree.
22944 * @param {Node} node
22947 setRootNode : function(node){
22949 node.ownerTree = this;
22950 node.isRoot = true;
22951 this.registerNode(node);
22956 * Gets a node in this tree by its id.
22957 * @param {String} id
22960 getNodeById : function(id){
22961 return this.nodeHash[id];
22964 registerNode : function(node){
22965 this.nodeHash[node.id] = node;
22968 unregisterNode : function(node){
22969 delete this.nodeHash[node.id];
22972 toString : function(){
22973 return "[Tree"+(this.id?" "+this.id:"")+"]";
22978 * @class Roo.data.Node
22979 * @extends Roo.util.Observable
22980 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
22981 * @cfg {String} id The id for this node. If one is not specified, one is generated.
22983 * @param {Object} attributes The attributes/config for the node
22985 Roo.data.Node = function(attributes){
22987 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
22990 this.attributes = attributes || {};
22991 this.leaf = this.attributes.leaf;
22993 * The node id. @type String
22995 this.id = this.attributes.id;
22997 this.id = Roo.id(null, "ynode-");
22998 this.attributes.id = this.id;
23003 * All child nodes of this node. @type Array
23005 this.childNodes = [];
23006 if(!this.childNodes.indexOf){ // indexOf is a must
23007 this.childNodes.indexOf = function(o){
23008 for(var i = 0, len = this.length; i < len; i++){
23017 * The parent node for this node. @type Node
23019 this.parentNode = null;
23021 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23023 this.firstChild = null;
23025 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23027 this.lastChild = null;
23029 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23031 this.previousSibling = null;
23033 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23035 this.nextSibling = null;
23040 * Fires when a new child node is appended
23041 * @param {Tree} tree The owner tree
23042 * @param {Node} this This node
23043 * @param {Node} node The newly appended node
23044 * @param {Number} index The index of the newly appended node
23049 * Fires when a child node is removed
23050 * @param {Tree} tree The owner tree
23051 * @param {Node} this This node
23052 * @param {Node} node The removed node
23057 * Fires when this node is moved to a new location in the tree
23058 * @param {Tree} tree The owner tree
23059 * @param {Node} this This node
23060 * @param {Node} oldParent The old parent of this node
23061 * @param {Node} newParent The new parent of this node
23062 * @param {Number} index The index it was moved to
23067 * Fires when a new child node is inserted.
23068 * @param {Tree} tree The owner tree
23069 * @param {Node} this This node
23070 * @param {Node} node The child node inserted
23071 * @param {Node} refNode The child node the node was inserted before
23075 * @event beforeappend
23076 * Fires before a new child is appended, return false to cancel the append.
23077 * @param {Tree} tree The owner tree
23078 * @param {Node} this This node
23079 * @param {Node} node The child node to be appended
23081 "beforeappend" : true,
23083 * @event beforeremove
23084 * Fires before a child is removed, return false to cancel the remove.
23085 * @param {Tree} tree The owner tree
23086 * @param {Node} this This node
23087 * @param {Node} node The child node to be removed
23089 "beforeremove" : true,
23091 * @event beforemove
23092 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23093 * @param {Tree} tree The owner tree
23094 * @param {Node} this This node
23095 * @param {Node} oldParent The parent of this node
23096 * @param {Node} newParent The new parent this node is moving to
23097 * @param {Number} index The index it is being moved to
23099 "beforemove" : true,
23101 * @event beforeinsert
23102 * Fires before a new child is inserted, return false to cancel the insert.
23103 * @param {Tree} tree The owner tree
23104 * @param {Node} this This node
23105 * @param {Node} node The child node to be inserted
23106 * @param {Node} refNode The child node the node is being inserted before
23108 "beforeinsert" : true
23110 this.listeners = this.attributes.listeners;
23111 Roo.data.Node.superclass.constructor.call(this);
23114 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23115 fireEvent : function(evtName){
23116 // first do standard event for this node
23117 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23120 // then bubble it up to the tree if the event wasn't cancelled
23121 var ot = this.getOwnerTree();
23123 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23131 * Returns true if this node is a leaf
23132 * @return {Boolean}
23134 isLeaf : function(){
23135 return this.leaf === true;
23139 setFirstChild : function(node){
23140 this.firstChild = node;
23144 setLastChild : function(node){
23145 this.lastChild = node;
23150 * Returns true if this node is the last child of its parent
23151 * @return {Boolean}
23153 isLast : function(){
23154 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23158 * Returns true if this node is the first child of its parent
23159 * @return {Boolean}
23161 isFirst : function(){
23162 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23165 hasChildNodes : function(){
23166 return !this.isLeaf() && this.childNodes.length > 0;
23170 * Insert node(s) as the last child node of this node.
23171 * @param {Node/Array} node The node or Array of nodes to append
23172 * @return {Node} The appended node if single append, or null if an array was passed
23174 appendChild : function(node){
23176 if(node instanceof Array){
23178 }else if(arguments.length > 1){
23181 // if passed an array or multiple args do them one by one
23183 for(var i = 0, len = multi.length; i < len; i++) {
23184 this.appendChild(multi[i]);
23187 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23190 var index = this.childNodes.length;
23191 var oldParent = node.parentNode;
23192 // it's a move, make sure we move it cleanly
23194 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23197 oldParent.removeChild(node);
23199 index = this.childNodes.length;
23201 this.setFirstChild(node);
23203 this.childNodes.push(node);
23204 node.parentNode = this;
23205 var ps = this.childNodes[index-1];
23207 node.previousSibling = ps;
23208 ps.nextSibling = node;
23210 node.previousSibling = null;
23212 node.nextSibling = null;
23213 this.setLastChild(node);
23214 node.setOwnerTree(this.getOwnerTree());
23215 this.fireEvent("append", this.ownerTree, this, node, index);
23217 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23224 * Removes a child node from this node.
23225 * @param {Node} node The node to remove
23226 * @return {Node} The removed node
23228 removeChild : function(node){
23229 var index = this.childNodes.indexOf(node);
23233 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23237 // remove it from childNodes collection
23238 this.childNodes.splice(index, 1);
23241 if(node.previousSibling){
23242 node.previousSibling.nextSibling = node.nextSibling;
23244 if(node.nextSibling){
23245 node.nextSibling.previousSibling = node.previousSibling;
23248 // update child refs
23249 if(this.firstChild == node){
23250 this.setFirstChild(node.nextSibling);
23252 if(this.lastChild == node){
23253 this.setLastChild(node.previousSibling);
23256 node.setOwnerTree(null);
23257 // clear any references from the node
23258 node.parentNode = null;
23259 node.previousSibling = null;
23260 node.nextSibling = null;
23261 this.fireEvent("remove", this.ownerTree, this, node);
23266 * Inserts the first node before the second node in this nodes childNodes collection.
23267 * @param {Node} node The node to insert
23268 * @param {Node} refNode The node to insert before (if null the node is appended)
23269 * @return {Node} The inserted node
23271 insertBefore : function(node, refNode){
23272 if(!refNode){ // like standard Dom, refNode can be null for append
23273 return this.appendChild(node);
23276 if(node == refNode){
23280 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23283 var index = this.childNodes.indexOf(refNode);
23284 var oldParent = node.parentNode;
23285 var refIndex = index;
23287 // when moving internally, indexes will change after remove
23288 if(oldParent == this && this.childNodes.indexOf(node) < index){
23292 // it's a move, make sure we move it cleanly
23294 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23297 oldParent.removeChild(node);
23300 this.setFirstChild(node);
23302 this.childNodes.splice(refIndex, 0, node);
23303 node.parentNode = this;
23304 var ps = this.childNodes[refIndex-1];
23306 node.previousSibling = ps;
23307 ps.nextSibling = node;
23309 node.previousSibling = null;
23311 node.nextSibling = refNode;
23312 refNode.previousSibling = node;
23313 node.setOwnerTree(this.getOwnerTree());
23314 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23316 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23322 * Returns the child node at the specified index.
23323 * @param {Number} index
23326 item : function(index){
23327 return this.childNodes[index];
23331 * Replaces one child node in this node with another.
23332 * @param {Node} newChild The replacement node
23333 * @param {Node} oldChild The node to replace
23334 * @return {Node} The replaced node
23336 replaceChild : function(newChild, oldChild){
23337 this.insertBefore(newChild, oldChild);
23338 this.removeChild(oldChild);
23343 * Returns the index of a child node
23344 * @param {Node} node
23345 * @return {Number} The index of the node or -1 if it was not found
23347 indexOf : function(child){
23348 return this.childNodes.indexOf(child);
23352 * Returns the tree this node is in.
23355 getOwnerTree : function(){
23356 // if it doesn't have one, look for one
23357 if(!this.ownerTree){
23361 this.ownerTree = p.ownerTree;
23367 return this.ownerTree;
23371 * Returns depth of this node (the root node has a depth of 0)
23374 getDepth : function(){
23377 while(p.parentNode){
23385 setOwnerTree : function(tree){
23386 // if it's move, we need to update everyone
23387 if(tree != this.ownerTree){
23388 if(this.ownerTree){
23389 this.ownerTree.unregisterNode(this);
23391 this.ownerTree = tree;
23392 var cs = this.childNodes;
23393 for(var i = 0, len = cs.length; i < len; i++) {
23394 cs[i].setOwnerTree(tree);
23397 tree.registerNode(this);
23403 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23404 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23405 * @return {String} The path
23407 getPath : function(attr){
23408 attr = attr || "id";
23409 var p = this.parentNode;
23410 var b = [this.attributes[attr]];
23412 b.unshift(p.attributes[attr]);
23415 var sep = this.getOwnerTree().pathSeparator;
23416 return sep + b.join(sep);
23420 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23421 * function call will be the scope provided or the current node. The arguments to the function
23422 * will be the args provided or the current node. If the function returns false at any point,
23423 * the bubble is stopped.
23424 * @param {Function} fn The function to call
23425 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23426 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23428 bubble : function(fn, scope, args){
23431 if(fn.call(scope || p, args || p) === false){
23439 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23440 * function call will be the scope provided or the current node. The arguments to the function
23441 * will be the args provided or the current node. If the function returns false at any point,
23442 * the cascade is stopped on that branch.
23443 * @param {Function} fn The function to call
23444 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23445 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23447 cascade : function(fn, scope, args){
23448 if(fn.call(scope || this, args || this) !== false){
23449 var cs = this.childNodes;
23450 for(var i = 0, len = cs.length; i < len; i++) {
23451 cs[i].cascade(fn, scope, args);
23457 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23458 * function call will be the scope provided or the current node. The arguments to the function
23459 * will be the args provided or the current node. If the function returns false at any point,
23460 * the iteration stops.
23461 * @param {Function} fn The function to call
23462 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23463 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23465 eachChild : function(fn, scope, args){
23466 var cs = this.childNodes;
23467 for(var i = 0, len = cs.length; i < len; i++) {
23468 if(fn.call(scope || this, args || cs[i]) === false){
23475 * Finds the first child that has the attribute with the specified value.
23476 * @param {String} attribute The attribute name
23477 * @param {Mixed} value The value to search for
23478 * @return {Node} The found child or null if none was found
23480 findChild : function(attribute, value){
23481 var cs = this.childNodes;
23482 for(var i = 0, len = cs.length; i < len; i++) {
23483 if(cs[i].attributes[attribute] == value){
23491 * Finds the first child by a custom function. The child matches if the function passed
23493 * @param {Function} fn
23494 * @param {Object} scope (optional)
23495 * @return {Node} The found child or null if none was found
23497 findChildBy : function(fn, scope){
23498 var cs = this.childNodes;
23499 for(var i = 0, len = cs.length; i < len; i++) {
23500 if(fn.call(scope||cs[i], cs[i]) === true){
23508 * Sorts this nodes children using the supplied sort function
23509 * @param {Function} fn
23510 * @param {Object} scope (optional)
23512 sort : function(fn, scope){
23513 var cs = this.childNodes;
23514 var len = cs.length;
23516 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23518 for(var i = 0; i < len; i++){
23520 n.previousSibling = cs[i-1];
23521 n.nextSibling = cs[i+1];
23523 this.setFirstChild(n);
23526 this.setLastChild(n);
23533 * Returns true if this node is an ancestor (at any point) of the passed node.
23534 * @param {Node} node
23535 * @return {Boolean}
23537 contains : function(node){
23538 return node.isAncestor(this);
23542 * Returns true if the passed node is an ancestor (at any point) of this node.
23543 * @param {Node} node
23544 * @return {Boolean}
23546 isAncestor : function(node){
23547 var p = this.parentNode;
23557 toString : function(){
23558 return "[Node"+(this.id?" "+this.id:"")+"]";
23562 * Ext JS Library 1.1.1
23563 * Copyright(c) 2006-2007, Ext JS, LLC.
23565 * Originally Released Under LGPL - original licence link has changed is not relivant.
23568 * <script type="text/javascript">
23573 * @extends Roo.Element
23574 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23575 * automatic maintaining of shadow/shim positions.
23576 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23577 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23578 * you can pass a string with a CSS class name. False turns off the shadow.
23579 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23580 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23581 * @cfg {String} cls CSS class to add to the element
23582 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23583 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23585 * @param {Object} config An object with config options.
23586 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23589 Roo.Layer = function(config, existingEl){
23590 config = config || {};
23591 var dh = Roo.DomHelper;
23592 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23594 this.dom = Roo.getDom(existingEl);
23597 var o = config.dh || {tag: "div", cls: "x-layer"};
23598 this.dom = dh.append(pel, o);
23601 this.addClass(config.cls);
23603 this.constrain = config.constrain !== false;
23604 this.visibilityMode = Roo.Element.VISIBILITY;
23606 this.id = this.dom.id = config.id;
23608 this.id = Roo.id(this.dom);
23610 this.zindex = config.zindex || this.getZIndex();
23611 this.position("absolute", this.zindex);
23613 this.shadowOffset = config.shadowOffset || 4;
23614 this.shadow = new Roo.Shadow({
23615 offset : this.shadowOffset,
23616 mode : config.shadow
23619 this.shadowOffset = 0;
23621 this.useShim = config.shim !== false && Roo.useShims;
23622 this.useDisplay = config.useDisplay;
23626 var supr = Roo.Element.prototype;
23628 // shims are shared among layer to keep from having 100 iframes
23631 Roo.extend(Roo.Layer, Roo.Element, {
23633 getZIndex : function(){
23634 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23637 getShim : function(){
23644 var shim = shims.shift();
23646 shim = this.createShim();
23647 shim.enableDisplayMode('block');
23648 shim.dom.style.display = 'none';
23649 shim.dom.style.visibility = 'visible';
23651 var pn = this.dom.parentNode;
23652 if(shim.dom.parentNode != pn){
23653 pn.insertBefore(shim.dom, this.dom);
23655 shim.setStyle('z-index', this.getZIndex()-2);
23660 hideShim : function(){
23662 this.shim.setDisplayed(false);
23663 shims.push(this.shim);
23668 disableShadow : function(){
23670 this.shadowDisabled = true;
23671 this.shadow.hide();
23672 this.lastShadowOffset = this.shadowOffset;
23673 this.shadowOffset = 0;
23677 enableShadow : function(show){
23679 this.shadowDisabled = false;
23680 this.shadowOffset = this.lastShadowOffset;
23681 delete this.lastShadowOffset;
23689 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23690 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23691 sync : function(doShow){
23692 var sw = this.shadow;
23693 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23694 var sh = this.getShim();
23696 var w = this.getWidth(),
23697 h = this.getHeight();
23699 var l = this.getLeft(true),
23700 t = this.getTop(true);
23702 if(sw && !this.shadowDisabled){
23703 if(doShow && !sw.isVisible()){
23706 sw.realign(l, t, w, h);
23712 // fit the shim behind the shadow, so it is shimmed too
23713 var a = sw.adjusts, s = sh.dom.style;
23714 s.left = (Math.min(l, l+a.l))+"px";
23715 s.top = (Math.min(t, t+a.t))+"px";
23716 s.width = (w+a.w)+"px";
23717 s.height = (h+a.h)+"px";
23724 sh.setLeftTop(l, t);
23731 destroy : function(){
23734 this.shadow.hide();
23736 this.removeAllListeners();
23737 var pn = this.dom.parentNode;
23739 pn.removeChild(this.dom);
23741 Roo.Element.uncache(this.id);
23744 remove : function(){
23749 beginUpdate : function(){
23750 this.updating = true;
23754 endUpdate : function(){
23755 this.updating = false;
23760 hideUnders : function(negOffset){
23762 this.shadow.hide();
23768 constrainXY : function(){
23769 if(this.constrain){
23770 var vw = Roo.lib.Dom.getViewWidth(),
23771 vh = Roo.lib.Dom.getViewHeight();
23772 var s = Roo.get(document).getScroll();
23774 var xy = this.getXY();
23775 var x = xy[0], y = xy[1];
23776 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23777 // only move it if it needs it
23779 // first validate right/bottom
23780 if((x + w) > vw+s.left){
23781 x = vw - w - this.shadowOffset;
23784 if((y + h) > vh+s.top){
23785 y = vh - h - this.shadowOffset;
23788 // then make sure top/left isn't negative
23799 var ay = this.avoidY;
23800 if(y <= ay && (y+h) >= ay){
23806 supr.setXY.call(this, xy);
23812 isVisible : function(){
23813 return this.visible;
23817 showAction : function(){
23818 this.visible = true; // track visibility to prevent getStyle calls
23819 if(this.useDisplay === true){
23820 this.setDisplayed("");
23821 }else if(this.lastXY){
23822 supr.setXY.call(this, this.lastXY);
23823 }else if(this.lastLT){
23824 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23829 hideAction : function(){
23830 this.visible = false;
23831 if(this.useDisplay === true){
23832 this.setDisplayed(false);
23834 this.setLeftTop(-10000,-10000);
23838 // overridden Element method
23839 setVisible : function(v, a, d, c, e){
23844 var cb = function(){
23849 }.createDelegate(this);
23850 supr.setVisible.call(this, true, true, d, cb, e);
23853 this.hideUnders(true);
23862 }.createDelegate(this);
23864 supr.setVisible.call(this, v, a, d, cb, e);
23873 storeXY : function(xy){
23874 delete this.lastLT;
23878 storeLeftTop : function(left, top){
23879 delete this.lastXY;
23880 this.lastLT = [left, top];
23884 beforeFx : function(){
23885 this.beforeAction();
23886 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23890 afterFx : function(){
23891 Roo.Layer.superclass.afterFx.apply(this, arguments);
23892 this.sync(this.isVisible());
23896 beforeAction : function(){
23897 if(!this.updating && this.shadow){
23898 this.shadow.hide();
23902 // overridden Element method
23903 setLeft : function(left){
23904 this.storeLeftTop(left, this.getTop(true));
23905 supr.setLeft.apply(this, arguments);
23909 setTop : function(top){
23910 this.storeLeftTop(this.getLeft(true), top);
23911 supr.setTop.apply(this, arguments);
23915 setLeftTop : function(left, top){
23916 this.storeLeftTop(left, top);
23917 supr.setLeftTop.apply(this, arguments);
23921 setXY : function(xy, a, d, c, e){
23923 this.beforeAction();
23925 var cb = this.createCB(c);
23926 supr.setXY.call(this, xy, a, d, cb, e);
23933 createCB : function(c){
23944 // overridden Element method
23945 setX : function(x, a, d, c, e){
23946 this.setXY([x, this.getY()], a, d, c, e);
23949 // overridden Element method
23950 setY : function(y, a, d, c, e){
23951 this.setXY([this.getX(), y], a, d, c, e);
23954 // overridden Element method
23955 setSize : function(w, h, a, d, c, e){
23956 this.beforeAction();
23957 var cb = this.createCB(c);
23958 supr.setSize.call(this, w, h, a, d, cb, e);
23964 // overridden Element method
23965 setWidth : function(w, a, d, c, e){
23966 this.beforeAction();
23967 var cb = this.createCB(c);
23968 supr.setWidth.call(this, w, a, d, cb, e);
23974 // overridden Element method
23975 setHeight : function(h, a, d, c, e){
23976 this.beforeAction();
23977 var cb = this.createCB(c);
23978 supr.setHeight.call(this, h, a, d, cb, e);
23984 // overridden Element method
23985 setBounds : function(x, y, w, h, a, d, c, e){
23986 this.beforeAction();
23987 var cb = this.createCB(c);
23989 this.storeXY([x, y]);
23990 supr.setXY.call(this, [x, y]);
23991 supr.setSize.call(this, w, h, a, d, cb, e);
23994 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24000 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24001 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24002 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24003 * @param {Number} zindex The new z-index to set
24004 * @return {this} The Layer
24006 setZIndex : function(zindex){
24007 this.zindex = zindex;
24008 this.setStyle("z-index", zindex + 2);
24010 this.shadow.setZIndex(zindex + 1);
24013 this.shim.setStyle("z-index", zindex);
24019 * Ext JS Library 1.1.1
24020 * Copyright(c) 2006-2007, Ext JS, LLC.
24022 * Originally Released Under LGPL - original licence link has changed is not relivant.
24025 * <script type="text/javascript">
24030 * @class Roo.Shadow
24031 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24032 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24033 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24035 * Create a new Shadow
24036 * @param {Object} config The config object
24038 Roo.Shadow = function(config){
24039 Roo.apply(this, config);
24040 if(typeof this.mode != "string"){
24041 this.mode = this.defaultMode;
24043 var o = this.offset, a = {h: 0};
24044 var rad = Math.floor(this.offset/2);
24045 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24051 a.l -= this.offset + rad;
24052 a.t -= this.offset + rad;
24063 a.l -= (this.offset - rad);
24064 a.t -= this.offset + rad;
24066 a.w -= (this.offset - rad)*2;
24077 a.l -= (this.offset - rad);
24078 a.t -= (this.offset - rad);
24080 a.w -= (this.offset + rad + 1);
24081 a.h -= (this.offset + rad);
24090 Roo.Shadow.prototype = {
24092 * @cfg {String} mode
24093 * The shadow display mode. Supports the following options:<br />
24094 * sides: Shadow displays on both sides and bottom only<br />
24095 * frame: Shadow displays equally on all four sides<br />
24096 * drop: Traditional bottom-right drop shadow (default)
24099 * @cfg {String} offset
24100 * The number of pixels to offset the shadow from the element (defaults to 4)
24105 defaultMode: "drop",
24108 * Displays the shadow under the target element
24109 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24111 show : function(target){
24112 target = Roo.get(target);
24114 this.el = Roo.Shadow.Pool.pull();
24115 if(this.el.dom.nextSibling != target.dom){
24116 this.el.insertBefore(target);
24119 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24121 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24124 target.getLeft(true),
24125 target.getTop(true),
24129 this.el.dom.style.display = "block";
24133 * Returns true if the shadow is visible, else false
24135 isVisible : function(){
24136 return this.el ? true : false;
24140 * Direct alignment when values are already available. Show must be called at least once before
24141 * calling this method to ensure it is initialized.
24142 * @param {Number} left The target element left position
24143 * @param {Number} top The target element top position
24144 * @param {Number} width The target element width
24145 * @param {Number} height The target element height
24147 realign : function(l, t, w, h){
24151 var a = this.adjusts, d = this.el.dom, s = d.style;
24153 s.left = (l+a.l)+"px";
24154 s.top = (t+a.t)+"px";
24155 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24157 if(s.width != sws || s.height != shs){
24161 var cn = d.childNodes;
24162 var sww = Math.max(0, (sw-12))+"px";
24163 cn[0].childNodes[1].style.width = sww;
24164 cn[1].childNodes[1].style.width = sww;
24165 cn[2].childNodes[1].style.width = sww;
24166 cn[1].style.height = Math.max(0, (sh-12))+"px";
24172 * Hides this shadow
24176 this.el.dom.style.display = "none";
24177 Roo.Shadow.Pool.push(this.el);
24183 * Adjust the z-index of this shadow
24184 * @param {Number} zindex The new z-index
24186 setZIndex : function(z){
24189 this.el.setStyle("z-index", z);
24194 // Private utility class that manages the internal Shadow cache
24195 Roo.Shadow.Pool = function(){
24197 var markup = Roo.isIE ?
24198 '<div class="x-ie-shadow"></div>' :
24199 '<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>';
24202 var sh = p.shift();
24204 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24205 sh.autoBoxAdjust = false;
24210 push : function(sh){
24216 * Ext JS Library 1.1.1
24217 * Copyright(c) 2006-2007, Ext JS, LLC.
24219 * Originally Released Under LGPL - original licence link has changed is not relivant.
24222 * <script type="text/javascript">
24227 * @class Roo.SplitBar
24228 * @extends Roo.util.Observable
24229 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24233 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24234 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24235 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24236 split.minSize = 100;
24237 split.maxSize = 600;
24238 split.animate = true;
24239 split.on('moved', splitterMoved);
24242 * Create a new SplitBar
24243 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24244 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24245 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24246 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24247 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24248 position of the SplitBar).
24250 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24253 this.el = Roo.get(dragElement, true);
24254 this.el.dom.unselectable = "on";
24256 this.resizingEl = Roo.get(resizingElement, true);
24260 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24261 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24264 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24267 * The minimum size of the resizing element. (Defaults to 0)
24273 * The maximum size of the resizing element. (Defaults to 2000)
24276 this.maxSize = 2000;
24279 * Whether to animate the transition to the new size
24282 this.animate = false;
24285 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24288 this.useShim = false;
24293 if(!existingProxy){
24295 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24297 this.proxy = Roo.get(existingProxy).dom;
24300 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24303 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24306 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24309 this.dragSpecs = {};
24312 * @private The adapter to use to positon and resize elements
24314 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24315 this.adapter.init(this);
24317 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24319 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24320 this.el.addClass("x-splitbar-h");
24323 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24324 this.el.addClass("x-splitbar-v");
24330 * Fires when the splitter is moved (alias for {@link #event-moved})
24331 * @param {Roo.SplitBar} this
24332 * @param {Number} newSize the new width or height
24337 * Fires when the splitter is moved
24338 * @param {Roo.SplitBar} this
24339 * @param {Number} newSize the new width or height
24343 * @event beforeresize
24344 * Fires before the splitter is dragged
24345 * @param {Roo.SplitBar} this
24347 "beforeresize" : true,
24349 "beforeapply" : true
24352 Roo.util.Observable.call(this);
24355 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24356 onStartProxyDrag : function(x, y){
24357 this.fireEvent("beforeresize", this);
24359 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24361 o.enableDisplayMode("block");
24362 // all splitbars share the same overlay
24363 Roo.SplitBar.prototype.overlay = o;
24365 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24366 this.overlay.show();
24367 Roo.get(this.proxy).setDisplayed("block");
24368 var size = this.adapter.getElementSize(this);
24369 this.activeMinSize = this.getMinimumSize();;
24370 this.activeMaxSize = this.getMaximumSize();;
24371 var c1 = size - this.activeMinSize;
24372 var c2 = Math.max(this.activeMaxSize - size, 0);
24373 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24374 this.dd.resetConstraints();
24375 this.dd.setXConstraint(
24376 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24377 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24379 this.dd.setYConstraint(0, 0);
24381 this.dd.resetConstraints();
24382 this.dd.setXConstraint(0, 0);
24383 this.dd.setYConstraint(
24384 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24385 this.placement == Roo.SplitBar.TOP ? c2 : c1
24388 this.dragSpecs.startSize = size;
24389 this.dragSpecs.startPoint = [x, y];
24390 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24394 * @private Called after the drag operation by the DDProxy
24396 onEndProxyDrag : function(e){
24397 Roo.get(this.proxy).setDisplayed(false);
24398 var endPoint = Roo.lib.Event.getXY(e);
24400 this.overlay.hide();
24403 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24404 newSize = this.dragSpecs.startSize +
24405 (this.placement == Roo.SplitBar.LEFT ?
24406 endPoint[0] - this.dragSpecs.startPoint[0] :
24407 this.dragSpecs.startPoint[0] - endPoint[0]
24410 newSize = this.dragSpecs.startSize +
24411 (this.placement == Roo.SplitBar.TOP ?
24412 endPoint[1] - this.dragSpecs.startPoint[1] :
24413 this.dragSpecs.startPoint[1] - endPoint[1]
24416 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24417 if(newSize != this.dragSpecs.startSize){
24418 if(this.fireEvent('beforeapply', this, newSize) !== false){
24419 this.adapter.setElementSize(this, newSize);
24420 this.fireEvent("moved", this, newSize);
24421 this.fireEvent("resize", this, newSize);
24427 * Get the adapter this SplitBar uses
24428 * @return The adapter object
24430 getAdapter : function(){
24431 return this.adapter;
24435 * Set the adapter this SplitBar uses
24436 * @param {Object} adapter A SplitBar adapter object
24438 setAdapter : function(adapter){
24439 this.adapter = adapter;
24440 this.adapter.init(this);
24444 * Gets the minimum size for the resizing element
24445 * @return {Number} The minimum size
24447 getMinimumSize : function(){
24448 return this.minSize;
24452 * Sets the minimum size for the resizing element
24453 * @param {Number} minSize The minimum size
24455 setMinimumSize : function(minSize){
24456 this.minSize = minSize;
24460 * Gets the maximum size for the resizing element
24461 * @return {Number} The maximum size
24463 getMaximumSize : function(){
24464 return this.maxSize;
24468 * Sets the maximum size for the resizing element
24469 * @param {Number} maxSize The maximum size
24471 setMaximumSize : function(maxSize){
24472 this.maxSize = maxSize;
24476 * Sets the initialize size for the resizing element
24477 * @param {Number} size The initial size
24479 setCurrentSize : function(size){
24480 var oldAnimate = this.animate;
24481 this.animate = false;
24482 this.adapter.setElementSize(this, size);
24483 this.animate = oldAnimate;
24487 * Destroy this splitbar.
24488 * @param {Boolean} removeEl True to remove the element
24490 destroy : function(removeEl){
24492 this.shim.remove();
24495 this.proxy.parentNode.removeChild(this.proxy);
24503 * @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.
24505 Roo.SplitBar.createProxy = function(dir){
24506 var proxy = new Roo.Element(document.createElement("div"));
24507 proxy.unselectable();
24508 var cls = 'x-splitbar-proxy';
24509 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24510 document.body.appendChild(proxy.dom);
24515 * @class Roo.SplitBar.BasicLayoutAdapter
24516 * Default Adapter. It assumes the splitter and resizing element are not positioned
24517 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24519 Roo.SplitBar.BasicLayoutAdapter = function(){
24522 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24523 // do nothing for now
24524 init : function(s){
24528 * Called before drag operations to get the current size of the resizing element.
24529 * @param {Roo.SplitBar} s The SplitBar using this adapter
24531 getElementSize : function(s){
24532 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24533 return s.resizingEl.getWidth();
24535 return s.resizingEl.getHeight();
24540 * Called after drag operations to set the size of the resizing element.
24541 * @param {Roo.SplitBar} s The SplitBar using this adapter
24542 * @param {Number} newSize The new size to set
24543 * @param {Function} onComplete A function to be invoked when resizing is complete
24545 setElementSize : function(s, newSize, onComplete){
24546 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24548 s.resizingEl.setWidth(newSize);
24550 onComplete(s, newSize);
24553 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24558 s.resizingEl.setHeight(newSize);
24560 onComplete(s, newSize);
24563 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24570 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24571 * @extends Roo.SplitBar.BasicLayoutAdapter
24572 * Adapter that moves the splitter element to align with the resized sizing element.
24573 * Used with an absolute positioned SplitBar.
24574 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24575 * document.body, make sure you assign an id to the body element.
24577 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24578 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24579 this.container = Roo.get(container);
24582 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24583 init : function(s){
24584 this.basic.init(s);
24587 getElementSize : function(s){
24588 return this.basic.getElementSize(s);
24591 setElementSize : function(s, newSize, onComplete){
24592 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24595 moveSplitter : function(s){
24596 var yes = Roo.SplitBar;
24597 switch(s.placement){
24599 s.el.setX(s.resizingEl.getRight());
24602 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24605 s.el.setY(s.resizingEl.getBottom());
24608 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24615 * Orientation constant - Create a vertical SplitBar
24619 Roo.SplitBar.VERTICAL = 1;
24622 * Orientation constant - Create a horizontal SplitBar
24626 Roo.SplitBar.HORIZONTAL = 2;
24629 * Placement constant - The resizing element is to the left of the splitter element
24633 Roo.SplitBar.LEFT = 1;
24636 * Placement constant - The resizing element is to the right of the splitter element
24640 Roo.SplitBar.RIGHT = 2;
24643 * Placement constant - The resizing element is positioned above the splitter element
24647 Roo.SplitBar.TOP = 3;
24650 * Placement constant - The resizing element is positioned under splitter element
24654 Roo.SplitBar.BOTTOM = 4;
24657 * Ext JS Library 1.1.1
24658 * Copyright(c) 2006-2007, Ext JS, LLC.
24660 * Originally Released Under LGPL - original licence link has changed is not relivant.
24663 * <script type="text/javascript">
24668 * @extends Roo.util.Observable
24669 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24670 * This class also supports single and multi selection modes. <br>
24671 * Create a data model bound view:
24673 var store = new Roo.data.Store(...);
24675 var view = new Roo.View({
24677 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24679 singleSelect: true,
24680 selectedClass: "ydataview-selected",
24684 // listen for node click?
24685 view.on("click", function(vw, index, node, e){
24686 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24690 dataModel.load("foobar.xml");
24692 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24694 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24695 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24697 * Note: old style constructor is still suported (container, template, config)
24700 * Create a new View
24701 * @param {Object} config The config object
24704 Roo.View = function(config, depreciated_tpl, depreciated_config){
24706 if (typeof(depreciated_tpl) == 'undefined') {
24707 // new way.. - universal constructor.
24708 Roo.apply(this, config);
24709 this.el = Roo.get(this.el);
24712 this.el = Roo.get(config);
24713 this.tpl = depreciated_tpl;
24714 Roo.apply(this, depreciated_config);
24716 this.wrapEl = this.el.wrap().wrap();
24717 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24720 if(typeof(this.tpl) == "string"){
24721 this.tpl = new Roo.Template(this.tpl);
24723 // support xtype ctors..
24724 this.tpl = new Roo.factory(this.tpl, Roo);
24728 this.tpl.compile();
24736 * @event beforeclick
24737 * Fires before a click is processed. Returns false to cancel the default action.
24738 * @param {Roo.View} this
24739 * @param {Number} index The index of the target node
24740 * @param {HTMLElement} node The target node
24741 * @param {Roo.EventObject} e The raw event object
24743 "beforeclick" : true,
24746 * Fires when a template node is clicked.
24747 * @param {Roo.View} this
24748 * @param {Number} index The index of the target node
24749 * @param {HTMLElement} node The target node
24750 * @param {Roo.EventObject} e The raw event object
24755 * Fires when a template node is double clicked.
24756 * @param {Roo.View} this
24757 * @param {Number} index The index of the target node
24758 * @param {HTMLElement} node The target node
24759 * @param {Roo.EventObject} e The raw event object
24763 * @event contextmenu
24764 * Fires when a template node is right clicked.
24765 * @param {Roo.View} this
24766 * @param {Number} index The index of the target node
24767 * @param {HTMLElement} node The target node
24768 * @param {Roo.EventObject} e The raw event object
24770 "contextmenu" : true,
24772 * @event selectionchange
24773 * Fires when the selected nodes change.
24774 * @param {Roo.View} this
24775 * @param {Array} selections Array of the selected nodes
24777 "selectionchange" : true,
24780 * @event beforeselect
24781 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24782 * @param {Roo.View} this
24783 * @param {HTMLElement} node The node to be selected
24784 * @param {Array} selections Array of currently selected nodes
24786 "beforeselect" : true,
24788 * @event preparedata
24789 * Fires on every row to render, to allow you to change the data.
24790 * @param {Roo.View} this
24791 * @param {Object} data to be rendered (change this)
24793 "preparedata" : true
24801 "click": this.onClick,
24802 "dblclick": this.onDblClick,
24803 "contextmenu": this.onContextMenu,
24807 this.selections = [];
24809 this.cmp = new Roo.CompositeElementLite([]);
24811 this.store = Roo.factory(this.store, Roo.data);
24812 this.setStore(this.store, true);
24815 if ( this.footer && this.footer.xtype) {
24817 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24819 this.footer.dataSource = this.store
24820 this.footer.container = fctr;
24821 this.footer = Roo.factory(this.footer, Roo);
24822 fctr.insertFirst(this.el);
24824 // this is a bit insane - as the paging toolbar seems to detach the el..
24825 // dom.parentNode.parentNode.parentNode
24826 // they get detached?
24830 Roo.View.superclass.constructor.call(this);
24835 Roo.extend(Roo.View, Roo.util.Observable, {
24838 * @cfg {Roo.data.Store} store Data store to load data from.
24843 * @cfg {String|Roo.Element} el The container element.
24848 * @cfg {String|Roo.Template} tpl The template used by this View
24852 * @cfg {String} dataName the named area of the template to use as the data area
24853 * Works with domtemplates roo-name="name"
24857 * @cfg {String} selectedClass The css class to add to selected nodes
24859 selectedClass : "x-view-selected",
24861 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24866 * @cfg {String} text to display on mask (default Loading)
24870 * @cfg {Boolean} multiSelect Allow multiple selection
24872 multiSelect : false,
24874 * @cfg {Boolean} singleSelect Allow single selection
24876 singleSelect: false,
24879 * @cfg {Boolean} toggleSelect - selecting
24881 toggleSelect : false,
24884 * Returns the element this view is bound to.
24885 * @return {Roo.Element}
24887 getEl : function(){
24888 return this.wrapEl;
24894 * Refreshes the view. - called by datachanged on the store. - do not call directly.
24896 refresh : function(){
24899 // if we are using something like 'domtemplate', then
24900 // the what gets used is:
24901 // t.applySubtemplate(NAME, data, wrapping data..)
24902 // the outer template then get' applied with
24903 // the store 'extra data'
24904 // and the body get's added to the
24905 // roo-name="data" node?
24906 // <span class='roo-tpl-{name}'></span> ?????
24910 this.clearSelections();
24911 this.el.update("");
24913 var records = this.store.getRange();
24914 if(records.length < 1) {
24916 // is this valid?? = should it render a template??
24918 this.el.update(this.emptyText);
24922 if (this.dataName) {
24923 this.el.update(t.apply(this.store.meta)); //????
24924 el = this.el.child('.roo-tpl-' + this.dataName);
24927 for(var i = 0, len = records.length; i < len; i++){
24928 var data = this.prepareData(records[i].data, i, records[i]);
24929 this.fireEvent("preparedata", this, data, i, records[i]);
24930 html[html.length] = Roo.util.Format.trim(
24932 t.applySubtemplate(this.dataName, data, this.store.meta) :
24939 el.update(html.join(""));
24940 this.nodes = el.dom.childNodes;
24941 this.updateIndexes(0);
24945 * Function to override to reformat the data that is sent to
24946 * the template for each node.
24947 * DEPRICATED - use the preparedata event handler.
24948 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
24949 * a JSON object for an UpdateManager bound view).
24951 prepareData : function(data, index, record)
24953 this.fireEvent("preparedata", this, data, index, record);
24957 onUpdate : function(ds, record){
24958 this.clearSelections();
24959 var index = this.store.indexOf(record);
24960 var n = this.nodes[index];
24961 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
24962 n.parentNode.removeChild(n);
24963 this.updateIndexes(index, index);
24969 onAdd : function(ds, records, index)
24971 this.clearSelections();
24972 if(this.nodes.length == 0){
24976 var n = this.nodes[index];
24977 for(var i = 0, len = records.length; i < len; i++){
24978 var d = this.prepareData(records[i].data, i, records[i]);
24980 this.tpl.insertBefore(n, d);
24983 this.tpl.append(this.el, d);
24986 this.updateIndexes(index);
24989 onRemove : function(ds, record, index){
24990 this.clearSelections();
24991 var el = this.dataName ?
24992 this.el.child('.roo-tpl-' + this.dataName) :
24994 el.dom.removeChild(this.nodes[index]);
24995 this.updateIndexes(index);
24999 * Refresh an individual node.
25000 * @param {Number} index
25002 refreshNode : function(index){
25003 this.onUpdate(this.store, this.store.getAt(index));
25006 updateIndexes : function(startIndex, endIndex){
25007 var ns = this.nodes;
25008 startIndex = startIndex || 0;
25009 endIndex = endIndex || ns.length - 1;
25010 for(var i = startIndex; i <= endIndex; i++){
25011 ns[i].nodeIndex = i;
25016 * Changes the data store this view uses and refresh the view.
25017 * @param {Store} store
25019 setStore : function(store, initial){
25020 if(!initial && this.store){
25021 this.store.un("datachanged", this.refresh);
25022 this.store.un("add", this.onAdd);
25023 this.store.un("remove", this.onRemove);
25024 this.store.un("update", this.onUpdate);
25025 this.store.un("clear", this.refresh);
25026 this.store.un("beforeload", this.onBeforeLoad);
25027 this.store.un("load", this.onLoad);
25028 this.store.un("loadexception", this.onLoad);
25032 store.on("datachanged", this.refresh, this);
25033 store.on("add", this.onAdd, this);
25034 store.on("remove", this.onRemove, this);
25035 store.on("update", this.onUpdate, this);
25036 store.on("clear", this.refresh, this);
25037 store.on("beforeload", this.onBeforeLoad, this);
25038 store.on("load", this.onLoad, this);
25039 store.on("loadexception", this.onLoad, this);
25047 * onbeforeLoad - masks the loading area.
25050 onBeforeLoad : function()
25052 this.el.update("");
25053 this.el.mask(this.mask ? this.mask : "Loading" );
25055 onLoad : function ()
25062 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25063 * @param {HTMLElement} node
25064 * @return {HTMLElement} The template node
25066 findItemFromChild : function(node){
25067 var el = this.dataName ?
25068 this.el.child('.roo-tpl-' + this.dataName,true) :
25071 if(!node || node.parentNode == el){
25074 var p = node.parentNode;
25075 while(p && p != el){
25076 if(p.parentNode == el){
25085 onClick : function(e){
25086 var item = this.findItemFromChild(e.getTarget());
25088 var index = this.indexOf(item);
25089 if(this.onItemClick(item, index, e) !== false){
25090 this.fireEvent("click", this, index, item, e);
25093 this.clearSelections();
25098 onContextMenu : function(e){
25099 var item = this.findItemFromChild(e.getTarget());
25101 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25106 onDblClick : function(e){
25107 var item = this.findItemFromChild(e.getTarget());
25109 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25113 onItemClick : function(item, index, e)
25115 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25118 if (this.toggleSelect) {
25119 var m = this.isSelected(item) ? 'unselect' : 'select';
25122 _t[m](item, true, false);
25125 if(this.multiSelect || this.singleSelect){
25126 if(this.multiSelect && e.shiftKey && this.lastSelection){
25127 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25129 this.select(item, this.multiSelect && e.ctrlKey);
25130 this.lastSelection = item;
25132 e.preventDefault();
25138 * Get the number of selected nodes.
25141 getSelectionCount : function(){
25142 return this.selections.length;
25146 * Get the currently selected nodes.
25147 * @return {Array} An array of HTMLElements
25149 getSelectedNodes : function(){
25150 return this.selections;
25154 * Get the indexes of the selected nodes.
25157 getSelectedIndexes : function(){
25158 var indexes = [], s = this.selections;
25159 for(var i = 0, len = s.length; i < len; i++){
25160 indexes.push(s[i].nodeIndex);
25166 * Clear all selections
25167 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25169 clearSelections : function(suppressEvent){
25170 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25171 this.cmp.elements = this.selections;
25172 this.cmp.removeClass(this.selectedClass);
25173 this.selections = [];
25174 if(!suppressEvent){
25175 this.fireEvent("selectionchange", this, this.selections);
25181 * Returns true if the passed node is selected
25182 * @param {HTMLElement/Number} node The node or node index
25183 * @return {Boolean}
25185 isSelected : function(node){
25186 var s = this.selections;
25190 node = this.getNode(node);
25191 return s.indexOf(node) !== -1;
25196 * @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
25197 * @param {Boolean} keepExisting (optional) true to keep existing selections
25198 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25200 select : function(nodeInfo, keepExisting, suppressEvent){
25201 if(nodeInfo instanceof Array){
25203 this.clearSelections(true);
25205 for(var i = 0, len = nodeInfo.length; i < len; i++){
25206 this.select(nodeInfo[i], true, true);
25210 var node = this.getNode(nodeInfo);
25211 if(!node || this.isSelected(node)){
25212 return; // already selected.
25215 this.clearSelections(true);
25217 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25218 Roo.fly(node).addClass(this.selectedClass);
25219 this.selections.push(node);
25220 if(!suppressEvent){
25221 this.fireEvent("selectionchange", this, this.selections);
25229 * @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
25230 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25231 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25233 unselect : function(nodeInfo, keepExisting, suppressEvent)
25235 if(nodeInfo instanceof Array){
25236 Roo.each(this.selections, function(s) {
25237 this.unselect(s, nodeInfo);
25241 var node = this.getNode(nodeInfo);
25242 if(!node || !this.isSelected(node)){
25243 Roo.log("not selected");
25244 return; // not selected.
25248 Roo.each(this.selections, function(s) {
25250 Roo.fly(node).removeClass(this.selectedClass);
25257 this.selections= ns;
25258 this.fireEvent("selectionchange", this, this.selections);
25262 * Gets a template node.
25263 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25264 * @return {HTMLElement} The node or null if it wasn't found
25266 getNode : function(nodeInfo){
25267 if(typeof nodeInfo == "string"){
25268 return document.getElementById(nodeInfo);
25269 }else if(typeof nodeInfo == "number"){
25270 return this.nodes[nodeInfo];
25276 * Gets a range template nodes.
25277 * @param {Number} startIndex
25278 * @param {Number} endIndex
25279 * @return {Array} An array of nodes
25281 getNodes : function(start, end){
25282 var ns = this.nodes;
25283 start = start || 0;
25284 end = typeof end == "undefined" ? ns.length - 1 : end;
25287 for(var i = start; i <= end; i++){
25291 for(var i = start; i >= end; i--){
25299 * Finds the index of the passed node
25300 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25301 * @return {Number} The index of the node or -1
25303 indexOf : function(node){
25304 node = this.getNode(node);
25305 if(typeof node.nodeIndex == "number"){
25306 return node.nodeIndex;
25308 var ns = this.nodes;
25309 for(var i = 0, len = ns.length; i < len; i++){
25319 * Ext JS Library 1.1.1
25320 * Copyright(c) 2006-2007, Ext JS, LLC.
25322 * Originally Released Under LGPL - original licence link has changed is not relivant.
25325 * <script type="text/javascript">
25329 * @class Roo.JsonView
25330 * @extends Roo.View
25331 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25333 var view = new Roo.JsonView({
25334 container: "my-element",
25335 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25340 // listen for node click?
25341 view.on("click", function(vw, index, node, e){
25342 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25345 // direct load of JSON data
25346 view.load("foobar.php");
25348 // Example from my blog list
25349 var tpl = new Roo.Template(
25350 '<div class="entry">' +
25351 '<a class="entry-title" href="{link}">{title}</a>' +
25352 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25353 "</div><hr />"
25356 var moreView = new Roo.JsonView({
25357 container : "entry-list",
25361 moreView.on("beforerender", this.sortEntries, this);
25363 url: "/blog/get-posts.php",
25364 params: "allposts=true",
25365 text: "Loading Blog Entries..."
25369 * Note: old code is supported with arguments : (container, template, config)
25373 * Create a new JsonView
25375 * @param {Object} config The config object
25378 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25381 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25383 var um = this.el.getUpdateManager();
25384 um.setRenderer(this);
25385 um.on("update", this.onLoad, this);
25386 um.on("failure", this.onLoadException, this);
25389 * @event beforerender
25390 * Fires before rendering of the downloaded JSON data.
25391 * @param {Roo.JsonView} this
25392 * @param {Object} data The JSON data loaded
25396 * Fires when data is loaded.
25397 * @param {Roo.JsonView} this
25398 * @param {Object} data The JSON data loaded
25399 * @param {Object} response The raw Connect response object
25402 * @event loadexception
25403 * Fires when loading fails.
25404 * @param {Roo.JsonView} this
25405 * @param {Object} response The raw Connect response object
25408 'beforerender' : true,
25410 'loadexception' : true
25413 Roo.extend(Roo.JsonView, Roo.View, {
25415 * @type {String} The root property in the loaded JSON object that contains the data
25420 * Refreshes the view.
25422 refresh : function(){
25423 this.clearSelections();
25424 this.el.update("");
25426 var o = this.jsonData;
25427 if(o && o.length > 0){
25428 for(var i = 0, len = o.length; i < len; i++){
25429 var data = this.prepareData(o[i], i, o);
25430 html[html.length] = this.tpl.apply(data);
25433 html.push(this.emptyText);
25435 this.el.update(html.join(""));
25436 this.nodes = this.el.dom.childNodes;
25437 this.updateIndexes(0);
25441 * 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.
25442 * @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:
25445 url: "your-url.php",
25446 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25447 callback: yourFunction,
25448 scope: yourObject, //(optional scope)
25451 text: "Loading...",
25456 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25457 * 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.
25458 * @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}
25459 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25460 * @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.
25463 var um = this.el.getUpdateManager();
25464 um.update.apply(um, arguments);
25467 render : function(el, response){
25468 this.clearSelections();
25469 this.el.update("");
25472 o = Roo.util.JSON.decode(response.responseText);
25475 o = o[this.jsonRoot];
25480 * The current JSON data or null
25483 this.beforeRender();
25488 * Get the number of records in the current JSON dataset
25491 getCount : function(){
25492 return this.jsonData ? this.jsonData.length : 0;
25496 * Returns the JSON object for the specified node(s)
25497 * @param {HTMLElement/Array} node The node or an array of nodes
25498 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25499 * you get the JSON object for the node
25501 getNodeData : function(node){
25502 if(node instanceof Array){
25504 for(var i = 0, len = node.length; i < len; i++){
25505 data.push(this.getNodeData(node[i]));
25509 return this.jsonData[this.indexOf(node)] || null;
25512 beforeRender : function(){
25513 this.snapshot = this.jsonData;
25515 this.sort.apply(this, this.sortInfo);
25517 this.fireEvent("beforerender", this, this.jsonData);
25520 onLoad : function(el, o){
25521 this.fireEvent("load", this, this.jsonData, o);
25524 onLoadException : function(el, o){
25525 this.fireEvent("loadexception", this, o);
25529 * Filter the data by a specific property.
25530 * @param {String} property A property on your JSON objects
25531 * @param {String/RegExp} value Either string that the property values
25532 * should start with, or a RegExp to test against the property
25534 filter : function(property, value){
25537 var ss = this.snapshot;
25538 if(typeof value == "string"){
25539 var vlen = value.length;
25541 this.clearFilter();
25544 value = value.toLowerCase();
25545 for(var i = 0, len = ss.length; i < len; i++){
25547 if(o[property].substr(0, vlen).toLowerCase() == value){
25551 } else if(value.exec){ // regex?
25552 for(var i = 0, len = ss.length; i < len; i++){
25554 if(value.test(o[property])){
25561 this.jsonData = data;
25567 * Filter by a function. The passed function will be called with each
25568 * object in the current dataset. If the function returns true the value is kept,
25569 * otherwise it is filtered.
25570 * @param {Function} fn
25571 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25573 filterBy : function(fn, scope){
25576 var ss = this.snapshot;
25577 for(var i = 0, len = ss.length; i < len; i++){
25579 if(fn.call(scope || this, o)){
25583 this.jsonData = data;
25589 * Clears the current filter.
25591 clearFilter : function(){
25592 if(this.snapshot && this.jsonData != this.snapshot){
25593 this.jsonData = this.snapshot;
25600 * Sorts the data for this view and refreshes it.
25601 * @param {String} property A property on your JSON objects to sort on
25602 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25603 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25605 sort : function(property, dir, sortType){
25606 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25609 var dsc = dir && dir.toLowerCase() == "desc";
25610 var f = function(o1, o2){
25611 var v1 = sortType ? sortType(o1[p]) : o1[p];
25612 var v2 = sortType ? sortType(o2[p]) : o2[p];
25615 return dsc ? +1 : -1;
25616 } else if(v1 > v2){
25617 return dsc ? -1 : +1;
25622 this.jsonData.sort(f);
25624 if(this.jsonData != this.snapshot){
25625 this.snapshot.sort(f);
25631 * Ext JS Library 1.1.1
25632 * Copyright(c) 2006-2007, Ext JS, LLC.
25634 * Originally Released Under LGPL - original licence link has changed is not relivant.
25637 * <script type="text/javascript">
25642 * @class Roo.ColorPalette
25643 * @extends Roo.Component
25644 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25645 * Here's an example of typical usage:
25647 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25648 cp.render('my-div');
25650 cp.on('select', function(palette, selColor){
25651 // do something with selColor
25655 * Create a new ColorPalette
25656 * @param {Object} config The config object
25658 Roo.ColorPalette = function(config){
25659 Roo.ColorPalette.superclass.constructor.call(this, config);
25663 * Fires when a color is selected
25664 * @param {ColorPalette} this
25665 * @param {String} color The 6-digit color hex code (without the # symbol)
25671 this.on("select", this.handler, this.scope, true);
25674 Roo.extend(Roo.ColorPalette, Roo.Component, {
25676 * @cfg {String} itemCls
25677 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25679 itemCls : "x-color-palette",
25681 * @cfg {String} value
25682 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25683 * the hex codes are case-sensitive.
25686 clickEvent:'click',
25688 ctype: "Roo.ColorPalette",
25691 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25693 allowReselect : false,
25696 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25697 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25698 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25699 * of colors with the width setting until the box is symmetrical.</p>
25700 * <p>You can override individual colors if needed:</p>
25702 var cp = new Roo.ColorPalette();
25703 cp.colors[0] = "FF0000"; // change the first box to red
25706 Or you can provide a custom array of your own for complete control:
25708 var cp = new Roo.ColorPalette();
25709 cp.colors = ["000000", "993300", "333300"];
25714 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25715 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25716 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25717 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25718 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25722 onRender : function(container, position){
25723 var t = new Roo.MasterTemplate(
25724 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25726 var c = this.colors;
25727 for(var i = 0, len = c.length; i < len; i++){
25730 var el = document.createElement("div");
25731 el.className = this.itemCls;
25733 container.dom.insertBefore(el, position);
25734 this.el = Roo.get(el);
25735 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25736 if(this.clickEvent != 'click'){
25737 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25742 afterRender : function(){
25743 Roo.ColorPalette.superclass.afterRender.call(this);
25745 var s = this.value;
25752 handleClick : function(e, t){
25753 e.preventDefault();
25754 if(!this.disabled){
25755 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25756 this.select(c.toUpperCase());
25761 * Selects the specified color in the palette (fires the select event)
25762 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25764 select : function(color){
25765 color = color.replace("#", "");
25766 if(color != this.value || this.allowReselect){
25769 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25771 el.child("a.color-"+color).addClass("x-color-palette-sel");
25772 this.value = color;
25773 this.fireEvent("select", this, color);
25778 * Ext JS Library 1.1.1
25779 * Copyright(c) 2006-2007, Ext JS, LLC.
25781 * Originally Released Under LGPL - original licence link has changed is not relivant.
25784 * <script type="text/javascript">
25788 * @class Roo.DatePicker
25789 * @extends Roo.Component
25790 * Simple date picker class.
25792 * Create a new DatePicker
25793 * @param {Object} config The config object
25795 Roo.DatePicker = function(config){
25796 Roo.DatePicker.superclass.constructor.call(this, config);
25798 this.value = config && config.value ?
25799 config.value.clearTime() : new Date().clearTime();
25804 * Fires when a date is selected
25805 * @param {DatePicker} this
25806 * @param {Date} date The selected date
25810 * @event monthchange
25811 * Fires when the displayed month changes
25812 * @param {DatePicker} this
25813 * @param {Date} date The selected month
25815 'monthchange': true
25819 this.on("select", this.handler, this.scope || this);
25821 // build the disabledDatesRE
25822 if(!this.disabledDatesRE && this.disabledDates){
25823 var dd = this.disabledDates;
25825 for(var i = 0; i < dd.length; i++){
25827 if(i != dd.length-1) re += "|";
25829 this.disabledDatesRE = new RegExp(re + ")");
25833 Roo.extend(Roo.DatePicker, Roo.Component, {
25835 * @cfg {String} todayText
25836 * The text to display on the button that selects the current date (defaults to "Today")
25838 todayText : "Today",
25840 * @cfg {String} okText
25841 * The text to display on the ok button
25843 okText : " OK ", //   to give the user extra clicking room
25845 * @cfg {String} cancelText
25846 * The text to display on the cancel button
25848 cancelText : "Cancel",
25850 * @cfg {String} todayTip
25851 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25853 todayTip : "{0} (Spacebar)",
25855 * @cfg {Date} minDate
25856 * Minimum allowable date (JavaScript date object, defaults to null)
25860 * @cfg {Date} maxDate
25861 * Maximum allowable date (JavaScript date object, defaults to null)
25865 * @cfg {String} minText
25866 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25868 minText : "This date is before the minimum date",
25870 * @cfg {String} maxText
25871 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25873 maxText : "This date is after the maximum date",
25875 * @cfg {String} format
25876 * The default date format string which can be overriden for localization support. The format must be
25877 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25881 * @cfg {Array} disabledDays
25882 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25884 disabledDays : null,
25886 * @cfg {String} disabledDaysText
25887 * The tooltip to display when the date falls on a disabled day (defaults to "")
25889 disabledDaysText : "",
25891 * @cfg {RegExp} disabledDatesRE
25892 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25894 disabledDatesRE : null,
25896 * @cfg {String} disabledDatesText
25897 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25899 disabledDatesText : "",
25901 * @cfg {Boolean} constrainToViewport
25902 * True to constrain the date picker to the viewport (defaults to true)
25904 constrainToViewport : true,
25906 * @cfg {Array} monthNames
25907 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25909 monthNames : Date.monthNames,
25911 * @cfg {Array} dayNames
25912 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25914 dayNames : Date.dayNames,
25916 * @cfg {String} nextText
25917 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25919 nextText: 'Next Month (Control+Right)',
25921 * @cfg {String} prevText
25922 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25924 prevText: 'Previous Month (Control+Left)',
25926 * @cfg {String} monthYearText
25927 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25929 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25931 * @cfg {Number} startDay
25932 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25936 * @cfg {Bool} showClear
25937 * Show a clear button (usefull for date form elements that can be blank.)
25943 * Sets the value of the date field
25944 * @param {Date} value The date to set
25946 setValue : function(value){
25947 var old = this.value;
25949 if (typeof(value) == 'string') {
25951 value = Date.parseDate(value, this.format);
25954 value = new Date();
25957 this.value = value.clearTime(true);
25959 this.update(this.value);
25964 * Gets the current selected value of the date field
25965 * @return {Date} The selected date
25967 getValue : function(){
25972 focus : function(){
25974 this.update(this.activeDate);
25979 onRender : function(container, position){
25982 '<table cellspacing="0">',
25983 '<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>',
25984 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
25985 var dn = this.dayNames;
25986 for(var i = 0; i < 7; i++){
25987 var d = this.startDay+i;
25991 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
25993 m[m.length] = "</tr></thead><tbody><tr>";
25994 for(var i = 0; i < 42; i++) {
25995 if(i % 7 == 0 && i != 0){
25996 m[m.length] = "</tr><tr>";
25998 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26000 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26001 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26003 var el = document.createElement("div");
26004 el.className = "x-date-picker";
26005 el.innerHTML = m.join("");
26007 container.dom.insertBefore(el, position);
26009 this.el = Roo.get(el);
26010 this.eventEl = Roo.get(el.firstChild);
26012 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26013 handler: this.showPrevMonth,
26015 preventDefault:true,
26019 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26020 handler: this.showNextMonth,
26022 preventDefault:true,
26026 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26028 this.monthPicker = this.el.down('div.x-date-mp');
26029 this.monthPicker.enableDisplayMode('block');
26031 var kn = new Roo.KeyNav(this.eventEl, {
26032 "left" : function(e){
26034 this.showPrevMonth() :
26035 this.update(this.activeDate.add("d", -1));
26038 "right" : function(e){
26040 this.showNextMonth() :
26041 this.update(this.activeDate.add("d", 1));
26044 "up" : function(e){
26046 this.showNextYear() :
26047 this.update(this.activeDate.add("d", -7));
26050 "down" : function(e){
26052 this.showPrevYear() :
26053 this.update(this.activeDate.add("d", 7));
26056 "pageUp" : function(e){
26057 this.showNextMonth();
26060 "pageDown" : function(e){
26061 this.showPrevMonth();
26064 "enter" : function(e){
26065 e.stopPropagation();
26072 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26074 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26076 this.el.unselectable();
26078 this.cells = this.el.select("table.x-date-inner tbody td");
26079 this.textNodes = this.el.query("table.x-date-inner tbody span");
26081 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26083 tooltip: this.monthYearText
26086 this.mbtn.on('click', this.showMonthPicker, this);
26087 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26090 var today = (new Date()).dateFormat(this.format);
26092 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26093 if (this.showClear) {
26094 baseTb.add( new Roo.Toolbar.Fill());
26097 text: String.format(this.todayText, today),
26098 tooltip: String.format(this.todayTip, today),
26099 handler: this.selectToday,
26103 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26106 if (this.showClear) {
26108 baseTb.add( new Roo.Toolbar.Fill());
26111 cls: 'x-btn-icon x-btn-clear',
26112 handler: function() {
26114 this.fireEvent("select", this, '');
26124 this.update(this.value);
26127 createMonthPicker : function(){
26128 if(!this.monthPicker.dom.firstChild){
26129 var buf = ['<table border="0" cellspacing="0">'];
26130 for(var i = 0; i < 6; i++){
26132 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26133 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26135 '<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>' :
26136 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26140 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26142 '</button><button type="button" class="x-date-mp-cancel">',
26144 '</button></td></tr>',
26147 this.monthPicker.update(buf.join(''));
26148 this.monthPicker.on('click', this.onMonthClick, this);
26149 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26151 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26152 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26154 this.mpMonths.each(function(m, a, i){
26157 m.dom.xmonth = 5 + Math.round(i * .5);
26159 m.dom.xmonth = Math.round((i-1) * .5);
26165 showMonthPicker : function(){
26166 this.createMonthPicker();
26167 var size = this.el.getSize();
26168 this.monthPicker.setSize(size);
26169 this.monthPicker.child('table').setSize(size);
26171 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26172 this.updateMPMonth(this.mpSelMonth);
26173 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26174 this.updateMPYear(this.mpSelYear);
26176 this.monthPicker.slideIn('t', {duration:.2});
26179 updateMPYear : function(y){
26181 var ys = this.mpYears.elements;
26182 for(var i = 1; i <= 10; i++){
26183 var td = ys[i-1], y2;
26185 y2 = y + Math.round(i * .5);
26186 td.firstChild.innerHTML = y2;
26189 y2 = y - (5-Math.round(i * .5));
26190 td.firstChild.innerHTML = y2;
26193 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26197 updateMPMonth : function(sm){
26198 this.mpMonths.each(function(m, a, i){
26199 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26203 selectMPMonth: function(m){
26207 onMonthClick : function(e, t){
26209 var el = new Roo.Element(t), pn;
26210 if(el.is('button.x-date-mp-cancel')){
26211 this.hideMonthPicker();
26213 else if(el.is('button.x-date-mp-ok')){
26214 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26215 this.hideMonthPicker();
26217 else if(pn = el.up('td.x-date-mp-month', 2)){
26218 this.mpMonths.removeClass('x-date-mp-sel');
26219 pn.addClass('x-date-mp-sel');
26220 this.mpSelMonth = pn.dom.xmonth;
26222 else if(pn = el.up('td.x-date-mp-year', 2)){
26223 this.mpYears.removeClass('x-date-mp-sel');
26224 pn.addClass('x-date-mp-sel');
26225 this.mpSelYear = pn.dom.xyear;
26227 else if(el.is('a.x-date-mp-prev')){
26228 this.updateMPYear(this.mpyear-10);
26230 else if(el.is('a.x-date-mp-next')){
26231 this.updateMPYear(this.mpyear+10);
26235 onMonthDblClick : function(e, t){
26237 var el = new Roo.Element(t), pn;
26238 if(pn = el.up('td.x-date-mp-month', 2)){
26239 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26240 this.hideMonthPicker();
26242 else if(pn = el.up('td.x-date-mp-year', 2)){
26243 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26244 this.hideMonthPicker();
26248 hideMonthPicker : function(disableAnim){
26249 if(this.monthPicker){
26250 if(disableAnim === true){
26251 this.monthPicker.hide();
26253 this.monthPicker.slideOut('t', {duration:.2});
26259 showPrevMonth : function(e){
26260 this.update(this.activeDate.add("mo", -1));
26264 showNextMonth : function(e){
26265 this.update(this.activeDate.add("mo", 1));
26269 showPrevYear : function(){
26270 this.update(this.activeDate.add("y", -1));
26274 showNextYear : function(){
26275 this.update(this.activeDate.add("y", 1));
26279 handleMouseWheel : function(e){
26280 var delta = e.getWheelDelta();
26282 this.showPrevMonth();
26284 } else if(delta < 0){
26285 this.showNextMonth();
26291 handleDateClick : function(e, t){
26293 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26294 this.setValue(new Date(t.dateValue));
26295 this.fireEvent("select", this, this.value);
26300 selectToday : function(){
26301 this.setValue(new Date().clearTime());
26302 this.fireEvent("select", this, this.value);
26306 update : function(date)
26308 var vd = this.activeDate;
26309 this.activeDate = date;
26311 var t = date.getTime();
26312 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26313 this.cells.removeClass("x-date-selected");
26314 this.cells.each(function(c){
26315 if(c.dom.firstChild.dateValue == t){
26316 c.addClass("x-date-selected");
26317 setTimeout(function(){
26318 try{c.dom.firstChild.focus();}catch(e){}
26327 var days = date.getDaysInMonth();
26328 var firstOfMonth = date.getFirstDateOfMonth();
26329 var startingPos = firstOfMonth.getDay()-this.startDay;
26331 if(startingPos <= this.startDay){
26335 var pm = date.add("mo", -1);
26336 var prevStart = pm.getDaysInMonth()-startingPos;
26338 var cells = this.cells.elements;
26339 var textEls = this.textNodes;
26340 days += startingPos;
26342 // convert everything to numbers so it's fast
26343 var day = 86400000;
26344 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26345 var today = new Date().clearTime().getTime();
26346 var sel = date.clearTime().getTime();
26347 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26348 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26349 var ddMatch = this.disabledDatesRE;
26350 var ddText = this.disabledDatesText;
26351 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26352 var ddaysText = this.disabledDaysText;
26353 var format = this.format;
26355 var setCellClass = function(cal, cell){
26357 var t = d.getTime();
26358 cell.firstChild.dateValue = t;
26360 cell.className += " x-date-today";
26361 cell.title = cal.todayText;
26364 cell.className += " x-date-selected";
26365 setTimeout(function(){
26366 try{cell.firstChild.focus();}catch(e){}
26371 cell.className = " x-date-disabled";
26372 cell.title = cal.minText;
26376 cell.className = " x-date-disabled";
26377 cell.title = cal.maxText;
26381 if(ddays.indexOf(d.getDay()) != -1){
26382 cell.title = ddaysText;
26383 cell.className = " x-date-disabled";
26386 if(ddMatch && format){
26387 var fvalue = d.dateFormat(format);
26388 if(ddMatch.test(fvalue)){
26389 cell.title = ddText.replace("%0", fvalue);
26390 cell.className = " x-date-disabled";
26396 for(; i < startingPos; i++) {
26397 textEls[i].innerHTML = (++prevStart);
26398 d.setDate(d.getDate()+1);
26399 cells[i].className = "x-date-prevday";
26400 setCellClass(this, cells[i]);
26402 for(; i < days; i++){
26403 intDay = i - startingPos + 1;
26404 textEls[i].innerHTML = (intDay);
26405 d.setDate(d.getDate()+1);
26406 cells[i].className = "x-date-active";
26407 setCellClass(this, cells[i]);
26410 for(; i < 42; i++) {
26411 textEls[i].innerHTML = (++extraDays);
26412 d.setDate(d.getDate()+1);
26413 cells[i].className = "x-date-nextday";
26414 setCellClass(this, cells[i]);
26417 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26418 this.fireEvent('monthchange', this, date);
26420 if(!this.internalRender){
26421 var main = this.el.dom.firstChild;
26422 var w = main.offsetWidth;
26423 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26424 Roo.fly(main).setWidth(w);
26425 this.internalRender = true;
26426 // opera does not respect the auto grow header center column
26427 // then, after it gets a width opera refuses to recalculate
26428 // without a second pass
26429 if(Roo.isOpera && !this.secondPass){
26430 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26431 this.secondPass = true;
26432 this.update.defer(10, this, [date]);
26440 * Ext JS Library 1.1.1
26441 * Copyright(c) 2006-2007, Ext JS, LLC.
26443 * Originally Released Under LGPL - original licence link has changed is not relivant.
26446 * <script type="text/javascript">
26449 * @class Roo.TabPanel
26450 * @extends Roo.util.Observable
26451 * A lightweight tab container.
26455 // basic tabs 1, built from existing content
26456 var tabs = new Roo.TabPanel("tabs1");
26457 tabs.addTab("script", "View Script");
26458 tabs.addTab("markup", "View Markup");
26459 tabs.activate("script");
26461 // more advanced tabs, built from javascript
26462 var jtabs = new Roo.TabPanel("jtabs");
26463 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26465 // set up the UpdateManager
26466 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26467 var updater = tab2.getUpdateManager();
26468 updater.setDefaultUrl("ajax1.htm");
26469 tab2.on('activate', updater.refresh, updater, true);
26471 // Use setUrl for Ajax loading
26472 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26473 tab3.setUrl("ajax2.htm", null, true);
26476 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26479 jtabs.activate("jtabs-1");
26482 * Create a new TabPanel.
26483 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26484 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26486 Roo.TabPanel = function(container, config){
26488 * The container element for this TabPanel.
26489 * @type Roo.Element
26491 this.el = Roo.get(container, true);
26493 if(typeof config == "boolean"){
26494 this.tabPosition = config ? "bottom" : "top";
26496 Roo.apply(this, config);
26499 if(this.tabPosition == "bottom"){
26500 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26501 this.el.addClass("x-tabs-bottom");
26503 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26504 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26505 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26507 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26509 if(this.tabPosition != "bottom"){
26510 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26511 * @type Roo.Element
26513 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26514 this.el.addClass("x-tabs-top");
26518 this.bodyEl.setStyle("position", "relative");
26520 this.active = null;
26521 this.activateDelegate = this.activate.createDelegate(this);
26526 * Fires when the active tab changes
26527 * @param {Roo.TabPanel} this
26528 * @param {Roo.TabPanelItem} activePanel The new active tab
26532 * @event beforetabchange
26533 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26534 * @param {Roo.TabPanel} this
26535 * @param {Object} e Set cancel to true on this object to cancel the tab change
26536 * @param {Roo.TabPanelItem} tab The tab being changed to
26538 "beforetabchange" : true
26541 Roo.EventManager.onWindowResize(this.onResize, this);
26542 this.cpad = this.el.getPadding("lr");
26543 this.hiddenCount = 0;
26546 // toolbar on the tabbar support...
26547 if (this.toolbar) {
26548 var tcfg = this.toolbar;
26549 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26550 this.toolbar = new Roo.Toolbar(tcfg);
26551 if (Roo.isSafari) {
26552 var tbl = tcfg.container.child('table', true);
26553 tbl.setAttribute('width', '100%');
26560 Roo.TabPanel.superclass.constructor.call(this);
26563 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26565 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26567 tabPosition : "top",
26569 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26571 currentTabWidth : 0,
26573 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26577 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26581 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26583 preferredTabWidth : 175,
26585 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26587 resizeTabs : false,
26589 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26591 monitorResize : true,
26593 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26598 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26599 * @param {String} id The id of the div to use <b>or create</b>
26600 * @param {String} text The text for the tab
26601 * @param {String} content (optional) Content to put in the TabPanelItem body
26602 * @param {Boolean} closable (optional) True to create a close icon on the tab
26603 * @return {Roo.TabPanelItem} The created TabPanelItem
26605 addTab : function(id, text, content, closable){
26606 var item = new Roo.TabPanelItem(this, id, text, closable);
26607 this.addTabItem(item);
26609 item.setContent(content);
26615 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26616 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26617 * @return {Roo.TabPanelItem}
26619 getTab : function(id){
26620 return this.items[id];
26624 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26625 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26627 hideTab : function(id){
26628 var t = this.items[id];
26631 this.hiddenCount++;
26632 this.autoSizeTabs();
26637 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26638 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26640 unhideTab : function(id){
26641 var t = this.items[id];
26643 t.setHidden(false);
26644 this.hiddenCount--;
26645 this.autoSizeTabs();
26650 * Adds an existing {@link Roo.TabPanelItem}.
26651 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26653 addTabItem : function(item){
26654 this.items[item.id] = item;
26655 this.items.push(item);
26656 if(this.resizeTabs){
26657 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26658 this.autoSizeTabs();
26665 * Removes a {@link Roo.TabPanelItem}.
26666 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26668 removeTab : function(id){
26669 var items = this.items;
26670 var tab = items[id];
26671 if(!tab) { return; }
26672 var index = items.indexOf(tab);
26673 if(this.active == tab && items.length > 1){
26674 var newTab = this.getNextAvailable(index);
26679 this.stripEl.dom.removeChild(tab.pnode.dom);
26680 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26681 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26683 items.splice(index, 1);
26684 delete this.items[tab.id];
26685 tab.fireEvent("close", tab);
26686 tab.purgeListeners();
26687 this.autoSizeTabs();
26690 getNextAvailable : function(start){
26691 var items = this.items;
26693 // look for a next tab that will slide over to
26694 // replace the one being removed
26695 while(index < items.length){
26696 var item = items[++index];
26697 if(item && !item.isHidden()){
26701 // if one isn't found select the previous tab (on the left)
26704 var item = items[--index];
26705 if(item && !item.isHidden()){
26713 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26714 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26716 disableTab : function(id){
26717 var tab = this.items[id];
26718 if(tab && this.active != tab){
26724 * Enables a {@link Roo.TabPanelItem} that is disabled.
26725 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26727 enableTab : function(id){
26728 var tab = this.items[id];
26733 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26734 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26735 * @return {Roo.TabPanelItem} The TabPanelItem.
26737 activate : function(id){
26738 var tab = this.items[id];
26742 if(tab == this.active || tab.disabled){
26746 this.fireEvent("beforetabchange", this, e, tab);
26747 if(e.cancel !== true && !tab.disabled){
26749 this.active.hide();
26751 this.active = this.items[id];
26752 this.active.show();
26753 this.fireEvent("tabchange", this, this.active);
26759 * Gets the active {@link Roo.TabPanelItem}.
26760 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26762 getActiveTab : function(){
26763 return this.active;
26767 * Updates the tab body element to fit the height of the container element
26768 * for overflow scrolling
26769 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26771 syncHeight : function(targetHeight){
26772 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26773 var bm = this.bodyEl.getMargins();
26774 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26775 this.bodyEl.setHeight(newHeight);
26779 onResize : function(){
26780 if(this.monitorResize){
26781 this.autoSizeTabs();
26786 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26788 beginUpdate : function(){
26789 this.updating = true;
26793 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26795 endUpdate : function(){
26796 this.updating = false;
26797 this.autoSizeTabs();
26801 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26803 autoSizeTabs : function(){
26804 var count = this.items.length;
26805 var vcount = count - this.hiddenCount;
26806 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26807 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26808 var availWidth = Math.floor(w / vcount);
26809 var b = this.stripBody;
26810 if(b.getWidth() > w){
26811 var tabs = this.items;
26812 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26813 if(availWidth < this.minTabWidth){
26814 /*if(!this.sleft){ // incomplete scrolling code
26815 this.createScrollButtons();
26818 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26821 if(this.currentTabWidth < this.preferredTabWidth){
26822 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26828 * Returns the number of tabs in this TabPanel.
26831 getCount : function(){
26832 return this.items.length;
26836 * Resizes all the tabs to the passed width
26837 * @param {Number} The new width
26839 setTabWidth : function(width){
26840 this.currentTabWidth = width;
26841 for(var i = 0, len = this.items.length; i < len; i++) {
26842 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26847 * Destroys this TabPanel
26848 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26850 destroy : function(removeEl){
26851 Roo.EventManager.removeResizeListener(this.onResize, this);
26852 for(var i = 0, len = this.items.length; i < len; i++){
26853 this.items[i].purgeListeners();
26855 if(removeEl === true){
26856 this.el.update("");
26863 * @class Roo.TabPanelItem
26864 * @extends Roo.util.Observable
26865 * Represents an individual item (tab plus body) in a TabPanel.
26866 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26867 * @param {String} id The id of this TabPanelItem
26868 * @param {String} text The text for the tab of this TabPanelItem
26869 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26871 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26873 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26874 * @type Roo.TabPanel
26876 this.tabPanel = tabPanel;
26878 * The id for this TabPanelItem
26883 this.disabled = false;
26887 this.loaded = false;
26888 this.closable = closable;
26891 * The body element for this TabPanelItem.
26892 * @type Roo.Element
26894 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26895 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26896 this.bodyEl.setStyle("display", "block");
26897 this.bodyEl.setStyle("zoom", "1");
26900 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26902 this.el = Roo.get(els.el, true);
26903 this.inner = Roo.get(els.inner, true);
26904 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26905 this.pnode = Roo.get(els.el.parentNode, true);
26906 this.el.on("mousedown", this.onTabMouseDown, this);
26907 this.el.on("click", this.onTabClick, this);
26910 var c = Roo.get(els.close, true);
26911 c.dom.title = this.closeText;
26912 c.addClassOnOver("close-over");
26913 c.on("click", this.closeClick, this);
26919 * Fires when this tab becomes the active tab.
26920 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26921 * @param {Roo.TabPanelItem} this
26925 * @event beforeclose
26926 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26927 * @param {Roo.TabPanelItem} this
26928 * @param {Object} e Set cancel to true on this object to cancel the close.
26930 "beforeclose": true,
26933 * Fires when this tab is closed.
26934 * @param {Roo.TabPanelItem} this
26938 * @event deactivate
26939 * Fires when this tab is no longer the active tab.
26940 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26941 * @param {Roo.TabPanelItem} this
26943 "deactivate" : true
26945 this.hidden = false;
26947 Roo.TabPanelItem.superclass.constructor.call(this);
26950 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
26951 purgeListeners : function(){
26952 Roo.util.Observable.prototype.purgeListeners.call(this);
26953 this.el.removeAllListeners();
26956 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
26959 this.pnode.addClass("on");
26962 this.tabPanel.stripWrap.repaint();
26964 this.fireEvent("activate", this.tabPanel, this);
26968 * Returns true if this tab is the active tab.
26969 * @return {Boolean}
26971 isActive : function(){
26972 return this.tabPanel.getActiveTab() == this;
26976 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
26979 this.pnode.removeClass("on");
26981 this.fireEvent("deactivate", this.tabPanel, this);
26984 hideAction : function(){
26985 this.bodyEl.hide();
26986 this.bodyEl.setStyle("position", "absolute");
26987 this.bodyEl.setLeft("-20000px");
26988 this.bodyEl.setTop("-20000px");
26991 showAction : function(){
26992 this.bodyEl.setStyle("position", "relative");
26993 this.bodyEl.setTop("");
26994 this.bodyEl.setLeft("");
26995 this.bodyEl.show();
26999 * Set the tooltip for the tab.
27000 * @param {String} tooltip The tab's tooltip
27002 setTooltip : function(text){
27003 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27004 this.textEl.dom.qtip = text;
27005 this.textEl.dom.removeAttribute('title');
27007 this.textEl.dom.title = text;
27011 onTabClick : function(e){
27012 e.preventDefault();
27013 this.tabPanel.activate(this.id);
27016 onTabMouseDown : function(e){
27017 e.preventDefault();
27018 this.tabPanel.activate(this.id);
27021 getWidth : function(){
27022 return this.inner.getWidth();
27025 setWidth : function(width){
27026 var iwidth = width - this.pnode.getPadding("lr");
27027 this.inner.setWidth(iwidth);
27028 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27029 this.pnode.setWidth(width);
27033 * Show or hide the tab
27034 * @param {Boolean} hidden True to hide or false to show.
27036 setHidden : function(hidden){
27037 this.hidden = hidden;
27038 this.pnode.setStyle("display", hidden ? "none" : "");
27042 * Returns true if this tab is "hidden"
27043 * @return {Boolean}
27045 isHidden : function(){
27046 return this.hidden;
27050 * Returns the text for this tab
27053 getText : function(){
27057 autoSize : function(){
27058 //this.el.beginMeasure();
27059 this.textEl.setWidth(1);
27060 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
27061 //this.el.endMeasure();
27065 * Sets the text for the tab (Note: this also sets the tooltip text)
27066 * @param {String} text The tab's text and tooltip
27068 setText : function(text){
27070 this.textEl.update(text);
27071 this.setTooltip(text);
27072 if(!this.tabPanel.resizeTabs){
27077 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27079 activate : function(){
27080 this.tabPanel.activate(this.id);
27084 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27086 disable : function(){
27087 if(this.tabPanel.active != this){
27088 this.disabled = true;
27089 this.pnode.addClass("disabled");
27094 * Enables this TabPanelItem if it was previously disabled.
27096 enable : function(){
27097 this.disabled = false;
27098 this.pnode.removeClass("disabled");
27102 * Sets the content for this TabPanelItem.
27103 * @param {String} content The content
27104 * @param {Boolean} loadScripts true to look for and load scripts
27106 setContent : function(content, loadScripts){
27107 this.bodyEl.update(content, loadScripts);
27111 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27112 * @return {Roo.UpdateManager} The UpdateManager
27114 getUpdateManager : function(){
27115 return this.bodyEl.getUpdateManager();
27119 * Set a URL to be used to load the content for this TabPanelItem.
27120 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27121 * @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)
27122 * @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)
27123 * @return {Roo.UpdateManager} The UpdateManager
27125 setUrl : function(url, params, loadOnce){
27126 if(this.refreshDelegate){
27127 this.un('activate', this.refreshDelegate);
27129 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27130 this.on("activate", this.refreshDelegate);
27131 return this.bodyEl.getUpdateManager();
27135 _handleRefresh : function(url, params, loadOnce){
27136 if(!loadOnce || !this.loaded){
27137 var updater = this.bodyEl.getUpdateManager();
27138 updater.update(url, params, this._setLoaded.createDelegate(this));
27143 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27144 * Will fail silently if the setUrl method has not been called.
27145 * This does not activate the panel, just updates its content.
27147 refresh : function(){
27148 if(this.refreshDelegate){
27149 this.loaded = false;
27150 this.refreshDelegate();
27155 _setLoaded : function(){
27156 this.loaded = true;
27160 closeClick : function(e){
27163 this.fireEvent("beforeclose", this, o);
27164 if(o.cancel !== true){
27165 this.tabPanel.removeTab(this.id);
27169 * The text displayed in the tooltip for the close icon.
27172 closeText : "Close this tab"
27176 Roo.TabPanel.prototype.createStrip = function(container){
27177 var strip = document.createElement("div");
27178 strip.className = "x-tabs-wrap";
27179 container.appendChild(strip);
27183 Roo.TabPanel.prototype.createStripList = function(strip){
27184 // div wrapper for retard IE
27185 // returns the "tr" element.
27186 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27187 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27188 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27189 return strip.firstChild.firstChild.firstChild.firstChild;
27192 Roo.TabPanel.prototype.createBody = function(container){
27193 var body = document.createElement("div");
27194 Roo.id(body, "tab-body");
27195 Roo.fly(body).addClass("x-tabs-body");
27196 container.appendChild(body);
27200 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27201 var body = Roo.getDom(id);
27203 body = document.createElement("div");
27206 Roo.fly(body).addClass("x-tabs-item-body");
27207 bodyEl.insertBefore(body, bodyEl.firstChild);
27211 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27212 var td = document.createElement("td");
27213 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27214 //stripEl.appendChild(td);
27216 td.className = "x-tabs-closable";
27217 if(!this.closeTpl){
27218 this.closeTpl = new Roo.Template(
27219 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27220 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27221 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27224 var el = this.closeTpl.overwrite(td, {"text": text});
27225 var close = el.getElementsByTagName("div")[0];
27226 var inner = el.getElementsByTagName("em")[0];
27227 return {"el": el, "close": close, "inner": inner};
27230 this.tabTpl = new Roo.Template(
27231 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27232 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27235 var el = this.tabTpl.overwrite(td, {"text": text});
27236 var inner = el.getElementsByTagName("em")[0];
27237 return {"el": el, "inner": inner};
27241 * Ext JS Library 1.1.1
27242 * Copyright(c) 2006-2007, Ext JS, LLC.
27244 * Originally Released Under LGPL - original licence link has changed is not relivant.
27247 * <script type="text/javascript">
27251 * @class Roo.Button
27252 * @extends Roo.util.Observable
27253 * Simple Button class
27254 * @cfg {String} text The button text
27255 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27256 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27257 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27258 * @cfg {Object} scope The scope of the handler
27259 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27260 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27261 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27262 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27263 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27264 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27265 applies if enableToggle = true)
27266 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27267 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27268 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27270 * Create a new button
27271 * @param {Object} config The config object
27273 Roo.Button = function(renderTo, config)
27277 renderTo = config.renderTo || false;
27280 Roo.apply(this, config);
27284 * Fires when this button is clicked
27285 * @param {Button} this
27286 * @param {EventObject} e The click event
27291 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27292 * @param {Button} this
27293 * @param {Boolean} pressed
27298 * Fires when the mouse hovers over the button
27299 * @param {Button} this
27300 * @param {Event} e The event object
27302 'mouseover' : true,
27305 * Fires when the mouse exits the button
27306 * @param {Button} this
27307 * @param {Event} e The event object
27312 * Fires when the button is rendered
27313 * @param {Button} this
27318 this.menu = Roo.menu.MenuMgr.get(this.menu);
27320 // register listeners first!! - so render can be captured..
27321 Roo.util.Observable.call(this);
27323 this.render(renderTo);
27329 Roo.extend(Roo.Button, Roo.util.Observable, {
27335 * Read-only. True if this button is hidden
27340 * Read-only. True if this button is disabled
27345 * Read-only. True if this button is pressed (only if enableToggle = true)
27351 * @cfg {Number} tabIndex
27352 * The DOM tabIndex for this button (defaults to undefined)
27354 tabIndex : undefined,
27357 * @cfg {Boolean} enableToggle
27358 * True to enable pressed/not pressed toggling (defaults to false)
27360 enableToggle: false,
27362 * @cfg {Mixed} menu
27363 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27367 * @cfg {String} menuAlign
27368 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27370 menuAlign : "tl-bl?",
27373 * @cfg {String} iconCls
27374 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27376 iconCls : undefined,
27378 * @cfg {String} type
27379 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27384 menuClassTarget: 'tr',
27387 * @cfg {String} clickEvent
27388 * The type of event to map to the button's event handler (defaults to 'click')
27390 clickEvent : 'click',
27393 * @cfg {Boolean} handleMouseEvents
27394 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27396 handleMouseEvents : true,
27399 * @cfg {String} tooltipType
27400 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27402 tooltipType : 'qtip',
27405 * @cfg {String} cls
27406 * A CSS class to apply to the button's main element.
27410 * @cfg {Roo.Template} template (Optional)
27411 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27412 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27413 * require code modifications if required elements (e.g. a button) aren't present.
27417 render : function(renderTo){
27419 if(this.hideParent){
27420 this.parentEl = Roo.get(renderTo);
27422 if(!this.dhconfig){
27423 if(!this.template){
27424 if(!Roo.Button.buttonTemplate){
27425 // hideous table template
27426 Roo.Button.buttonTemplate = new Roo.Template(
27427 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27428 '<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>',
27429 "</tr></tbody></table>");
27431 this.template = Roo.Button.buttonTemplate;
27433 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27434 var btnEl = btn.child("button:first");
27435 btnEl.on('focus', this.onFocus, this);
27436 btnEl.on('blur', this.onBlur, this);
27438 btn.addClass(this.cls);
27441 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27444 btnEl.addClass(this.iconCls);
27446 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27449 if(this.tabIndex !== undefined){
27450 btnEl.dom.tabIndex = this.tabIndex;
27453 if(typeof this.tooltip == 'object'){
27454 Roo.QuickTips.tips(Roo.apply({
27458 btnEl.dom[this.tooltipType] = this.tooltip;
27462 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27466 this.el.dom.id = this.el.id = this.id;
27469 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27470 this.menu.on("show", this.onMenuShow, this);
27471 this.menu.on("hide", this.onMenuHide, this);
27473 btn.addClass("x-btn");
27474 if(Roo.isIE && !Roo.isIE7){
27475 this.autoWidth.defer(1, this);
27479 if(this.handleMouseEvents){
27480 btn.on("mouseover", this.onMouseOver, this);
27481 btn.on("mouseout", this.onMouseOut, this);
27482 btn.on("mousedown", this.onMouseDown, this);
27484 btn.on(this.clickEvent, this.onClick, this);
27485 //btn.on("mouseup", this.onMouseUp, this);
27492 Roo.ButtonToggleMgr.register(this);
27494 this.el.addClass("x-btn-pressed");
27497 var repeater = new Roo.util.ClickRepeater(btn,
27498 typeof this.repeat == "object" ? this.repeat : {}
27500 repeater.on("click", this.onClick, this);
27503 this.fireEvent('render', this);
27507 * Returns the button's underlying element
27508 * @return {Roo.Element} The element
27510 getEl : function(){
27515 * Destroys this Button and removes any listeners.
27517 destroy : function(){
27518 Roo.ButtonToggleMgr.unregister(this);
27519 this.el.removeAllListeners();
27520 this.purgeListeners();
27525 autoWidth : function(){
27527 this.el.setWidth("auto");
27528 if(Roo.isIE7 && Roo.isStrict){
27529 var ib = this.el.child('button');
27530 if(ib && ib.getWidth() > 20){
27532 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27537 this.el.beginMeasure();
27539 if(this.el.getWidth() < this.minWidth){
27540 this.el.setWidth(this.minWidth);
27543 this.el.endMeasure();
27550 * Assigns this button's click handler
27551 * @param {Function} handler The function to call when the button is clicked
27552 * @param {Object} scope (optional) Scope for the function passed in
27554 setHandler : function(handler, scope){
27555 this.handler = handler;
27556 this.scope = scope;
27560 * Sets this button's text
27561 * @param {String} text The button text
27563 setText : function(text){
27566 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27572 * Gets the text for this button
27573 * @return {String} The button text
27575 getText : function(){
27583 this.hidden = false;
27585 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27593 this.hidden = true;
27595 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27600 * Convenience function for boolean show/hide
27601 * @param {Boolean} visible True to show, false to hide
27603 setVisible: function(visible){
27612 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27613 * @param {Boolean} state (optional) Force a particular state
27615 toggle : function(state){
27616 state = state === undefined ? !this.pressed : state;
27617 if(state != this.pressed){
27619 this.el.addClass("x-btn-pressed");
27620 this.pressed = true;
27621 this.fireEvent("toggle", this, true);
27623 this.el.removeClass("x-btn-pressed");
27624 this.pressed = false;
27625 this.fireEvent("toggle", this, false);
27627 if(this.toggleHandler){
27628 this.toggleHandler.call(this.scope || this, this, state);
27636 focus : function(){
27637 this.el.child('button:first').focus();
27641 * Disable this button
27643 disable : function(){
27645 this.el.addClass("x-btn-disabled");
27647 this.disabled = true;
27651 * Enable this button
27653 enable : function(){
27655 this.el.removeClass("x-btn-disabled");
27657 this.disabled = false;
27661 * Convenience function for boolean enable/disable
27662 * @param {Boolean} enabled True to enable, false to disable
27664 setDisabled : function(v){
27665 this[v !== true ? "enable" : "disable"]();
27669 onClick : function(e){
27671 e.preventDefault();
27676 if(!this.disabled){
27677 if(this.enableToggle){
27680 if(this.menu && !this.menu.isVisible()){
27681 this.menu.show(this.el, this.menuAlign);
27683 this.fireEvent("click", this, e);
27685 this.el.removeClass("x-btn-over");
27686 this.handler.call(this.scope || this, this, e);
27691 onMouseOver : function(e){
27692 if(!this.disabled){
27693 this.el.addClass("x-btn-over");
27694 this.fireEvent('mouseover', this, e);
27698 onMouseOut : function(e){
27699 if(!e.within(this.el, true)){
27700 this.el.removeClass("x-btn-over");
27701 this.fireEvent('mouseout', this, e);
27705 onFocus : function(e){
27706 if(!this.disabled){
27707 this.el.addClass("x-btn-focus");
27711 onBlur : function(e){
27712 this.el.removeClass("x-btn-focus");
27715 onMouseDown : function(e){
27716 if(!this.disabled && e.button == 0){
27717 this.el.addClass("x-btn-click");
27718 Roo.get(document).on('mouseup', this.onMouseUp, this);
27722 onMouseUp : function(e){
27724 this.el.removeClass("x-btn-click");
27725 Roo.get(document).un('mouseup', this.onMouseUp, this);
27729 onMenuShow : function(e){
27730 this.el.addClass("x-btn-menu-active");
27733 onMenuHide : function(e){
27734 this.el.removeClass("x-btn-menu-active");
27738 // Private utility class used by Button
27739 Roo.ButtonToggleMgr = function(){
27742 function toggleGroup(btn, state){
27744 var g = groups[btn.toggleGroup];
27745 for(var i = 0, l = g.length; i < l; i++){
27747 g[i].toggle(false);
27754 register : function(btn){
27755 if(!btn.toggleGroup){
27758 var g = groups[btn.toggleGroup];
27760 g = groups[btn.toggleGroup] = [];
27763 btn.on("toggle", toggleGroup);
27766 unregister : function(btn){
27767 if(!btn.toggleGroup){
27770 var g = groups[btn.toggleGroup];
27773 btn.un("toggle", toggleGroup);
27779 * Ext JS Library 1.1.1
27780 * Copyright(c) 2006-2007, Ext JS, LLC.
27782 * Originally Released Under LGPL - original licence link has changed is not relivant.
27785 * <script type="text/javascript">
27789 * @class Roo.SplitButton
27790 * @extends Roo.Button
27791 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27792 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27793 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27794 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27795 * @cfg {String} arrowTooltip The title attribute of the arrow
27797 * Create a new menu button
27798 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27799 * @param {Object} config The config object
27801 Roo.SplitButton = function(renderTo, config){
27802 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27804 * @event arrowclick
27805 * Fires when this button's arrow is clicked
27806 * @param {SplitButton} this
27807 * @param {EventObject} e The click event
27809 this.addEvents({"arrowclick":true});
27812 Roo.extend(Roo.SplitButton, Roo.Button, {
27813 render : function(renderTo){
27814 // this is one sweet looking template!
27815 var tpl = new Roo.Template(
27816 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27817 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27818 '<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>',
27819 "</tbody></table></td><td>",
27820 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27821 '<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>',
27822 "</tbody></table></td></tr></table>"
27824 var btn = tpl.append(renderTo, [this.text, this.type], true);
27825 var btnEl = btn.child("button");
27827 btn.addClass(this.cls);
27830 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27833 btnEl.addClass(this.iconCls);
27835 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27839 if(this.handleMouseEvents){
27840 btn.on("mouseover", this.onMouseOver, this);
27841 btn.on("mouseout", this.onMouseOut, this);
27842 btn.on("mousedown", this.onMouseDown, this);
27843 btn.on("mouseup", this.onMouseUp, this);
27845 btn.on(this.clickEvent, this.onClick, this);
27847 if(typeof this.tooltip == 'object'){
27848 Roo.QuickTips.tips(Roo.apply({
27852 btnEl.dom[this.tooltipType] = this.tooltip;
27855 if(this.arrowTooltip){
27856 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27865 this.el.addClass("x-btn-pressed");
27867 if(Roo.isIE && !Roo.isIE7){
27868 this.autoWidth.defer(1, this);
27873 this.menu.on("show", this.onMenuShow, this);
27874 this.menu.on("hide", this.onMenuHide, this);
27876 this.fireEvent('render', this);
27880 autoWidth : function(){
27882 var tbl = this.el.child("table:first");
27883 var tbl2 = this.el.child("table:last");
27884 this.el.setWidth("auto");
27885 tbl.setWidth("auto");
27886 if(Roo.isIE7 && Roo.isStrict){
27887 var ib = this.el.child('button:first');
27888 if(ib && ib.getWidth() > 20){
27890 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27895 this.el.beginMeasure();
27897 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27898 tbl.setWidth(this.minWidth-tbl2.getWidth());
27901 this.el.endMeasure();
27904 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27908 * Sets this button's click handler
27909 * @param {Function} handler The function to call when the button is clicked
27910 * @param {Object} scope (optional) Scope for the function passed above
27912 setHandler : function(handler, scope){
27913 this.handler = handler;
27914 this.scope = scope;
27918 * Sets this button's arrow click handler
27919 * @param {Function} handler The function to call when the arrow is clicked
27920 * @param {Object} scope (optional) Scope for the function passed above
27922 setArrowHandler : function(handler, scope){
27923 this.arrowHandler = handler;
27924 this.scope = scope;
27930 focus : function(){
27932 this.el.child("button:first").focus();
27937 onClick : function(e){
27938 e.preventDefault();
27939 if(!this.disabled){
27940 if(e.getTarget(".x-btn-menu-arrow-wrap")){
27941 if(this.menu && !this.menu.isVisible()){
27942 this.menu.show(this.el, this.menuAlign);
27944 this.fireEvent("arrowclick", this, e);
27945 if(this.arrowHandler){
27946 this.arrowHandler.call(this.scope || this, this, e);
27949 this.fireEvent("click", this, e);
27951 this.handler.call(this.scope || this, this, e);
27957 onMouseDown : function(e){
27958 if(!this.disabled){
27959 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
27963 onMouseUp : function(e){
27964 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
27969 // backwards compat
27970 Roo.MenuButton = Roo.SplitButton;/*
27972 * Ext JS Library 1.1.1
27973 * Copyright(c) 2006-2007, Ext JS, LLC.
27975 * Originally Released Under LGPL - original licence link has changed is not relivant.
27978 * <script type="text/javascript">
27982 * @class Roo.Toolbar
27983 * Basic Toolbar class.
27985 * Creates a new Toolbar
27986 * @param {Object} container The config object
27988 Roo.Toolbar = function(container, buttons, config)
27990 /// old consturctor format still supported..
27991 if(container instanceof Array){ // omit the container for later rendering
27992 buttons = container;
27996 if (typeof(container) == 'object' && container.xtype) {
27997 config = container;
27998 container = config.container;
27999 buttons = config.buttons || []; // not really - use items!!
28002 if (config && config.items) {
28003 xitems = config.items;
28004 delete config.items;
28006 Roo.apply(this, config);
28007 this.buttons = buttons;
28010 this.render(container);
28012 this.xitems = xitems;
28013 Roo.each(xitems, function(b) {
28019 Roo.Toolbar.prototype = {
28021 * @cfg {Array} items
28022 * array of button configs or elements to add (will be converted to a MixedCollection)
28026 * @cfg {String/HTMLElement/Element} container
28027 * The id or element that will contain the toolbar
28030 render : function(ct){
28031 this.el = Roo.get(ct);
28033 this.el.addClass(this.cls);
28035 // using a table allows for vertical alignment
28036 // 100% width is needed by Safari...
28037 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28038 this.tr = this.el.child("tr", true);
28040 this.items = new Roo.util.MixedCollection(false, function(o){
28041 return o.id || ("item" + (++autoId));
28044 this.add.apply(this, this.buttons);
28045 delete this.buttons;
28050 * Adds element(s) to the toolbar -- this function takes a variable number of
28051 * arguments of mixed type and adds them to the toolbar.
28052 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28054 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28055 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28056 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28057 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28058 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28059 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28060 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28061 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28062 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28064 * @param {Mixed} arg2
28065 * @param {Mixed} etc.
28068 var a = arguments, l = a.length;
28069 for(var i = 0; i < l; i++){
28074 _add : function(el) {
28077 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28080 if (el.applyTo){ // some kind of form field
28081 return this.addField(el);
28083 if (el.render){ // some kind of Toolbar.Item
28084 return this.addItem(el);
28086 if (typeof el == "string"){ // string
28087 if(el == "separator" || el == "-"){
28088 return this.addSeparator();
28091 return this.addSpacer();
28094 return this.addFill();
28096 return this.addText(el);
28099 if(el.tagName){ // element
28100 return this.addElement(el);
28102 if(typeof el == "object"){ // must be button config?
28103 return this.addButton(el);
28105 // and now what?!?!
28111 * Add an Xtype element
28112 * @param {Object} xtype Xtype Object
28113 * @return {Object} created Object
28115 addxtype : function(e){
28116 return this.add(e);
28120 * Returns the Element for this toolbar.
28121 * @return {Roo.Element}
28123 getEl : function(){
28129 * @return {Roo.Toolbar.Item} The separator item
28131 addSeparator : function(){
28132 return this.addItem(new Roo.Toolbar.Separator());
28136 * Adds a spacer element
28137 * @return {Roo.Toolbar.Spacer} The spacer item
28139 addSpacer : function(){
28140 return this.addItem(new Roo.Toolbar.Spacer());
28144 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28145 * @return {Roo.Toolbar.Fill} The fill item
28147 addFill : function(){
28148 return this.addItem(new Roo.Toolbar.Fill());
28152 * Adds any standard HTML element to the toolbar
28153 * @param {String/HTMLElement/Element} el The element or id of the element to add
28154 * @return {Roo.Toolbar.Item} The element's item
28156 addElement : function(el){
28157 return this.addItem(new Roo.Toolbar.Item(el));
28160 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28161 * @type Roo.util.MixedCollection
28166 * Adds any Toolbar.Item or subclass
28167 * @param {Roo.Toolbar.Item} item
28168 * @return {Roo.Toolbar.Item} The item
28170 addItem : function(item){
28171 var td = this.nextBlock();
28173 this.items.add(item);
28178 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28179 * @param {Object/Array} config A button config or array of configs
28180 * @return {Roo.Toolbar.Button/Array}
28182 addButton : function(config){
28183 if(config instanceof Array){
28185 for(var i = 0, len = config.length; i < len; i++) {
28186 buttons.push(this.addButton(config[i]));
28191 if(!(config instanceof Roo.Toolbar.Button)){
28193 new Roo.Toolbar.SplitButton(config) :
28194 new Roo.Toolbar.Button(config);
28196 var td = this.nextBlock();
28203 * Adds text to the toolbar
28204 * @param {String} text The text to add
28205 * @return {Roo.Toolbar.Item} The element's item
28207 addText : function(text){
28208 return this.addItem(new Roo.Toolbar.TextItem(text));
28212 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28213 * @param {Number} index The index where the item is to be inserted
28214 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28215 * @return {Roo.Toolbar.Button/Item}
28217 insertButton : function(index, item){
28218 if(item instanceof Array){
28220 for(var i = 0, len = item.length; i < len; i++) {
28221 buttons.push(this.insertButton(index + i, item[i]));
28225 if (!(item instanceof Roo.Toolbar.Button)){
28226 item = new Roo.Toolbar.Button(item);
28228 var td = document.createElement("td");
28229 this.tr.insertBefore(td, this.tr.childNodes[index]);
28231 this.items.insert(index, item);
28236 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28237 * @param {Object} config
28238 * @return {Roo.Toolbar.Item} The element's item
28240 addDom : function(config, returnEl){
28241 var td = this.nextBlock();
28242 Roo.DomHelper.overwrite(td, config);
28243 var ti = new Roo.Toolbar.Item(td.firstChild);
28245 this.items.add(ti);
28250 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28251 * @type Roo.util.MixedCollection
28256 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28257 * Note: the field should not have been rendered yet. For a field that has already been
28258 * rendered, use {@link #addElement}.
28259 * @param {Roo.form.Field} field
28260 * @return {Roo.ToolbarItem}
28264 addField : function(field) {
28265 if (!this.fields) {
28267 this.fields = new Roo.util.MixedCollection(false, function(o){
28268 return o.id || ("item" + (++autoId));
28273 var td = this.nextBlock();
28275 var ti = new Roo.Toolbar.Item(td.firstChild);
28277 this.items.add(ti);
28278 this.fields.add(field);
28289 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28290 this.el.child('div').hide();
28298 this.el.child('div').show();
28302 nextBlock : function(){
28303 var td = document.createElement("td");
28304 this.tr.appendChild(td);
28309 destroy : function(){
28310 if(this.items){ // rendered?
28311 Roo.destroy.apply(Roo, this.items.items);
28313 if(this.fields){ // rendered?
28314 Roo.destroy.apply(Roo, this.fields.items);
28316 Roo.Element.uncache(this.el, this.tr);
28321 * @class Roo.Toolbar.Item
28322 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28324 * Creates a new Item
28325 * @param {HTMLElement} el
28327 Roo.Toolbar.Item = function(el){
28328 this.el = Roo.getDom(el);
28329 this.id = Roo.id(this.el);
28330 this.hidden = false;
28333 Roo.Toolbar.Item.prototype = {
28336 * Get this item's HTML Element
28337 * @return {HTMLElement}
28339 getEl : function(){
28344 render : function(td){
28346 td.appendChild(this.el);
28350 * Removes and destroys this item.
28352 destroy : function(){
28353 this.td.parentNode.removeChild(this.td);
28360 this.hidden = false;
28361 this.td.style.display = "";
28368 this.hidden = true;
28369 this.td.style.display = "none";
28373 * Convenience function for boolean show/hide.
28374 * @param {Boolean} visible true to show/false to hide
28376 setVisible: function(visible){
28385 * Try to focus this item.
28387 focus : function(){
28388 Roo.fly(this.el).focus();
28392 * Disables this item.
28394 disable : function(){
28395 Roo.fly(this.td).addClass("x-item-disabled");
28396 this.disabled = true;
28397 this.el.disabled = true;
28401 * Enables this item.
28403 enable : function(){
28404 Roo.fly(this.td).removeClass("x-item-disabled");
28405 this.disabled = false;
28406 this.el.disabled = false;
28412 * @class Roo.Toolbar.Separator
28413 * @extends Roo.Toolbar.Item
28414 * A simple toolbar separator class
28416 * Creates a new Separator
28418 Roo.Toolbar.Separator = function(){
28419 var s = document.createElement("span");
28420 s.className = "ytb-sep";
28421 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
28423 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28424 enable:Roo.emptyFn,
28425 disable:Roo.emptyFn,
28430 * @class Roo.Toolbar.Spacer
28431 * @extends Roo.Toolbar.Item
28432 * A simple element that adds extra horizontal space to a toolbar.
28434 * Creates a new Spacer
28436 Roo.Toolbar.Spacer = function(){
28437 var s = document.createElement("div");
28438 s.className = "ytb-spacer";
28439 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
28441 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28442 enable:Roo.emptyFn,
28443 disable:Roo.emptyFn,
28448 * @class Roo.Toolbar.Fill
28449 * @extends Roo.Toolbar.Spacer
28450 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28452 * Creates a new Spacer
28454 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28456 render : function(td){
28457 td.style.width = '100%';
28458 Roo.Toolbar.Fill.superclass.render.call(this, td);
28463 * @class Roo.Toolbar.TextItem
28464 * @extends Roo.Toolbar.Item
28465 * A simple class that renders text directly into a toolbar.
28467 * Creates a new TextItem
28468 * @param {String} text
28470 Roo.Toolbar.TextItem = function(text){
28471 if (typeof(text) == 'object') {
28474 var s = document.createElement("span");
28475 s.className = "ytb-text";
28476 s.innerHTML = text;
28477 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28479 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28480 enable:Roo.emptyFn,
28481 disable:Roo.emptyFn,
28486 * @class Roo.Toolbar.Button
28487 * @extends Roo.Button
28488 * A button that renders into a toolbar.
28490 * Creates a new Button
28491 * @param {Object} config A standard {@link Roo.Button} config object
28493 Roo.Toolbar.Button = function(config){
28494 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28496 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28497 render : function(td){
28499 Roo.Toolbar.Button.superclass.render.call(this, td);
28503 * Removes and destroys this button
28505 destroy : function(){
28506 Roo.Toolbar.Button.superclass.destroy.call(this);
28507 this.td.parentNode.removeChild(this.td);
28511 * Shows this button
28514 this.hidden = false;
28515 this.td.style.display = "";
28519 * Hides this button
28522 this.hidden = true;
28523 this.td.style.display = "none";
28527 * Disables this item
28529 disable : function(){
28530 Roo.fly(this.td).addClass("x-item-disabled");
28531 this.disabled = true;
28535 * Enables this item
28537 enable : function(){
28538 Roo.fly(this.td).removeClass("x-item-disabled");
28539 this.disabled = false;
28542 // backwards compat
28543 Roo.ToolbarButton = Roo.Toolbar.Button;
28546 * @class Roo.Toolbar.SplitButton
28547 * @extends Roo.SplitButton
28548 * A menu button that renders into a toolbar.
28550 * Creates a new SplitButton
28551 * @param {Object} config A standard {@link Roo.SplitButton} config object
28553 Roo.Toolbar.SplitButton = function(config){
28554 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28556 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28557 render : function(td){
28559 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28563 * Removes and destroys this button
28565 destroy : function(){
28566 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28567 this.td.parentNode.removeChild(this.td);
28571 * Shows this button
28574 this.hidden = false;
28575 this.td.style.display = "";
28579 * Hides this button
28582 this.hidden = true;
28583 this.td.style.display = "none";
28587 // backwards compat
28588 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28590 * Ext JS Library 1.1.1
28591 * Copyright(c) 2006-2007, Ext JS, LLC.
28593 * Originally Released Under LGPL - original licence link has changed is not relivant.
28596 * <script type="text/javascript">
28600 * @class Roo.PagingToolbar
28601 * @extends Roo.Toolbar
28602 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28604 * Create a new PagingToolbar
28605 * @param {Object} config The config object
28607 Roo.PagingToolbar = function(el, ds, config)
28609 // old args format still supported... - xtype is prefered..
28610 if (typeof(el) == 'object' && el.xtype) {
28611 // created from xtype...
28613 ds = el.dataSource;
28614 el = config.container;
28617 if (config.items) {
28618 items = config.items;
28622 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28625 this.renderButtons(this.el);
28628 // supprot items array.
28630 Roo.each(items, function(e) {
28631 this.add(Roo.factory(e));
28636 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28638 * @cfg {Roo.data.Store} dataSource
28639 * The underlying data store providing the paged data
28642 * @cfg {String/HTMLElement/Element} container
28643 * container The id or element that will contain the toolbar
28646 * @cfg {Boolean} displayInfo
28647 * True to display the displayMsg (defaults to false)
28650 * @cfg {Number} pageSize
28651 * The number of records to display per page (defaults to 20)
28655 * @cfg {String} displayMsg
28656 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28658 displayMsg : 'Displaying {0} - {1} of {2}',
28660 * @cfg {String} emptyMsg
28661 * The message to display when no records are found (defaults to "No data to display")
28663 emptyMsg : 'No data to display',
28665 * Customizable piece of the default paging text (defaults to "Page")
28668 beforePageText : "Page",
28670 * Customizable piece of the default paging text (defaults to "of %0")
28673 afterPageText : "of {0}",
28675 * Customizable piece of the default paging text (defaults to "First Page")
28678 firstText : "First Page",
28680 * Customizable piece of the default paging text (defaults to "Previous Page")
28683 prevText : "Previous Page",
28685 * Customizable piece of the default paging text (defaults to "Next Page")
28688 nextText : "Next Page",
28690 * Customizable piece of the default paging text (defaults to "Last Page")
28693 lastText : "Last Page",
28695 * Customizable piece of the default paging text (defaults to "Refresh")
28698 refreshText : "Refresh",
28701 renderButtons : function(el){
28702 Roo.PagingToolbar.superclass.render.call(this, el);
28703 this.first = this.addButton({
28704 tooltip: this.firstText,
28705 cls: "x-btn-icon x-grid-page-first",
28707 handler: this.onClick.createDelegate(this, ["first"])
28709 this.prev = this.addButton({
28710 tooltip: this.prevText,
28711 cls: "x-btn-icon x-grid-page-prev",
28713 handler: this.onClick.createDelegate(this, ["prev"])
28715 //this.addSeparator();
28716 this.add(this.beforePageText);
28717 this.field = Roo.get(this.addDom({
28722 cls: "x-grid-page-number"
28724 this.field.on("keydown", this.onPagingKeydown, this);
28725 this.field.on("focus", function(){this.dom.select();});
28726 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28727 this.field.setHeight(18);
28728 //this.addSeparator();
28729 this.next = this.addButton({
28730 tooltip: this.nextText,
28731 cls: "x-btn-icon x-grid-page-next",
28733 handler: this.onClick.createDelegate(this, ["next"])
28735 this.last = this.addButton({
28736 tooltip: this.lastText,
28737 cls: "x-btn-icon x-grid-page-last",
28739 handler: this.onClick.createDelegate(this, ["last"])
28741 //this.addSeparator();
28742 this.loading = this.addButton({
28743 tooltip: this.refreshText,
28744 cls: "x-btn-icon x-grid-loading",
28745 handler: this.onClick.createDelegate(this, ["refresh"])
28748 if(this.displayInfo){
28749 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28754 updateInfo : function(){
28755 if(this.displayEl){
28756 var count = this.ds.getCount();
28757 var msg = count == 0 ?
28761 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28763 this.displayEl.update(msg);
28768 onLoad : function(ds, r, o){
28769 this.cursor = o.params ? o.params.start : 0;
28770 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28772 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28773 this.field.dom.value = ap;
28774 this.first.setDisabled(ap == 1);
28775 this.prev.setDisabled(ap == 1);
28776 this.next.setDisabled(ap == ps);
28777 this.last.setDisabled(ap == ps);
28778 this.loading.enable();
28783 getPageData : function(){
28784 var total = this.ds.getTotalCount();
28787 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28788 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28793 onLoadError : function(){
28794 this.loading.enable();
28798 onPagingKeydown : function(e){
28799 var k = e.getKey();
28800 var d = this.getPageData();
28802 var v = this.field.dom.value, pageNum;
28803 if(!v || isNaN(pageNum = parseInt(v, 10))){
28804 this.field.dom.value = d.activePage;
28807 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28808 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28811 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))
28813 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28814 this.field.dom.value = pageNum;
28815 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28818 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28820 var v = this.field.dom.value, pageNum;
28821 var increment = (e.shiftKey) ? 10 : 1;
28822 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28824 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28825 this.field.dom.value = d.activePage;
28828 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28830 this.field.dom.value = parseInt(v, 10) + increment;
28831 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28832 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28839 beforeLoad : function(){
28841 this.loading.disable();
28846 onClick : function(which){
28850 ds.load({params:{start: 0, limit: this.pageSize}});
28853 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28856 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28859 var total = ds.getTotalCount();
28860 var extra = total % this.pageSize;
28861 var lastStart = extra ? (total - extra) : total-this.pageSize;
28862 ds.load({params:{start: lastStart, limit: this.pageSize}});
28865 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28871 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28872 * @param {Roo.data.Store} store The data store to unbind
28874 unbind : function(ds){
28875 ds.un("beforeload", this.beforeLoad, this);
28876 ds.un("load", this.onLoad, this);
28877 ds.un("loadexception", this.onLoadError, this);
28878 ds.un("remove", this.updateInfo, this);
28879 ds.un("add", this.updateInfo, this);
28880 this.ds = undefined;
28884 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28885 * @param {Roo.data.Store} store The data store to bind
28887 bind : function(ds){
28888 ds.on("beforeload", this.beforeLoad, this);
28889 ds.on("load", this.onLoad, this);
28890 ds.on("loadexception", this.onLoadError, this);
28891 ds.on("remove", this.updateInfo, this);
28892 ds.on("add", this.updateInfo, this);
28897 * Ext JS Library 1.1.1
28898 * Copyright(c) 2006-2007, Ext JS, LLC.
28900 * Originally Released Under LGPL - original licence link has changed is not relivant.
28903 * <script type="text/javascript">
28907 * @class Roo.Resizable
28908 * @extends Roo.util.Observable
28909 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28910 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28911 * 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
28912 * the element will be wrapped for you automatically.</p>
28913 * <p>Here is the list of valid resize handles:</p>
28916 ------ -------------------
28925 'hd' horizontal drag
28928 * <p>Here's an example showing the creation of a typical Resizable:</p>
28930 var resizer = new Roo.Resizable("element-id", {
28938 resizer.on("resize", myHandler);
28940 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
28941 * resizer.east.setDisplayed(false);</p>
28942 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
28943 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
28944 * resize operation's new size (defaults to [0, 0])
28945 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
28946 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
28947 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
28948 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
28949 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
28950 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
28951 * @cfg {Number} width The width of the element in pixels (defaults to null)
28952 * @cfg {Number} height The height of the element in pixels (defaults to null)
28953 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
28954 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
28955 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
28956 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
28957 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
28958 * in favor of the handles config option (defaults to false)
28959 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
28960 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
28961 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
28962 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
28963 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
28964 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
28965 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
28966 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
28967 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
28968 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
28969 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
28971 * Create a new resizable component
28972 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
28973 * @param {Object} config configuration options
28975 Roo.Resizable = function(el, config)
28977 this.el = Roo.get(el);
28979 if(config && config.wrap){
28980 config.resizeChild = this.el;
28981 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
28982 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
28983 this.el.setStyle("overflow", "hidden");
28984 this.el.setPositioning(config.resizeChild.getPositioning());
28985 config.resizeChild.clearPositioning();
28986 if(!config.width || !config.height){
28987 var csize = config.resizeChild.getSize();
28988 this.el.setSize(csize.width, csize.height);
28990 if(config.pinned && !config.adjustments){
28991 config.adjustments = "auto";
28995 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
28996 this.proxy.unselectable();
28997 this.proxy.enableDisplayMode('block');
28999 Roo.apply(this, config);
29002 this.disableTrackOver = true;
29003 this.el.addClass("x-resizable-pinned");
29005 // if the element isn't positioned, make it relative
29006 var position = this.el.getStyle("position");
29007 if(position != "absolute" && position != "fixed"){
29008 this.el.setStyle("position", "relative");
29010 if(!this.handles){ // no handles passed, must be legacy style
29011 this.handles = 's,e,se';
29012 if(this.multiDirectional){
29013 this.handles += ',n,w';
29016 if(this.handles == "all"){
29017 this.handles = "n s e w ne nw se sw";
29019 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29020 var ps = Roo.Resizable.positions;
29021 for(var i = 0, len = hs.length; i < len; i++){
29022 if(hs[i] && ps[hs[i]]){
29023 var pos = ps[hs[i]];
29024 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29028 this.corner = this.southeast;
29030 // updateBox = the box can move..
29031 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29032 this.updateBox = true;
29035 this.activeHandle = null;
29037 if(this.resizeChild){
29038 if(typeof this.resizeChild == "boolean"){
29039 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29041 this.resizeChild = Roo.get(this.resizeChild, true);
29045 if(this.adjustments == "auto"){
29046 var rc = this.resizeChild;
29047 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29048 if(rc && (hw || hn)){
29049 rc.position("relative");
29050 rc.setLeft(hw ? hw.el.getWidth() : 0);
29051 rc.setTop(hn ? hn.el.getHeight() : 0);
29053 this.adjustments = [
29054 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29055 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29059 if(this.draggable){
29060 this.dd = this.dynamic ?
29061 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29062 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29068 * @event beforeresize
29069 * Fired before resize is allowed. Set enabled to false to cancel resize.
29070 * @param {Roo.Resizable} this
29071 * @param {Roo.EventObject} e The mousedown event
29073 "beforeresize" : true,
29076 * Fired a resizing.
29077 * @param {Roo.Resizable} this
29078 * @param {Number} x The new x position
29079 * @param {Number} y The new y position
29080 * @param {Number} w The new w width
29081 * @param {Number} h The new h hight
29082 * @param {Roo.EventObject} e The mouseup event
29087 * Fired after a resize.
29088 * @param {Roo.Resizable} this
29089 * @param {Number} width The new width
29090 * @param {Number} height The new height
29091 * @param {Roo.EventObject} e The mouseup event
29096 if(this.width !== null && this.height !== null){
29097 this.resizeTo(this.width, this.height);
29099 this.updateChildSize();
29102 this.el.dom.style.zoom = 1;
29104 Roo.Resizable.superclass.constructor.call(this);
29107 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29108 resizeChild : false,
29109 adjustments : [0, 0],
29119 multiDirectional : false,
29120 disableTrackOver : false,
29121 easing : 'easeOutStrong',
29122 widthIncrement : 0,
29123 heightIncrement : 0,
29127 preserveRatio : false,
29128 transparent: false,
29134 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29136 constrainTo: undefined,
29138 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29140 resizeRegion: undefined,
29144 * Perform a manual resize
29145 * @param {Number} width
29146 * @param {Number} height
29148 resizeTo : function(width, height){
29149 this.el.setSize(width, height);
29150 this.updateChildSize();
29151 this.fireEvent("resize", this, width, height, null);
29155 startSizing : function(e, handle){
29156 this.fireEvent("beforeresize", this, e);
29157 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29160 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29161 this.overlay.unselectable();
29162 this.overlay.enableDisplayMode("block");
29163 this.overlay.on("mousemove", this.onMouseMove, this);
29164 this.overlay.on("mouseup", this.onMouseUp, this);
29166 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29168 this.resizing = true;
29169 this.startBox = this.el.getBox();
29170 this.startPoint = e.getXY();
29171 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29172 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29174 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29175 this.overlay.show();
29177 if(this.constrainTo) {
29178 var ct = Roo.get(this.constrainTo);
29179 this.resizeRegion = ct.getRegion().adjust(
29180 ct.getFrameWidth('t'),
29181 ct.getFrameWidth('l'),
29182 -ct.getFrameWidth('b'),
29183 -ct.getFrameWidth('r')
29187 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29189 this.proxy.setBox(this.startBox);
29191 this.proxy.setStyle('visibility', 'visible');
29197 onMouseDown : function(handle, e){
29200 this.activeHandle = handle;
29201 this.startSizing(e, handle);
29206 onMouseUp : function(e){
29207 var size = this.resizeElement();
29208 this.resizing = false;
29210 this.overlay.hide();
29212 this.fireEvent("resize", this, size.width, size.height, e);
29216 updateChildSize : function(){
29218 if(this.resizeChild){
29220 var child = this.resizeChild;
29221 var adj = this.adjustments;
29222 if(el.dom.offsetWidth){
29223 var b = el.getSize(true);
29224 child.setSize(b.width+adj[0], b.height+adj[1]);
29226 // Second call here for IE
29227 // The first call enables instant resizing and
29228 // the second call corrects scroll bars if they
29231 setTimeout(function(){
29232 if(el.dom.offsetWidth){
29233 var b = el.getSize(true);
29234 child.setSize(b.width+adj[0], b.height+adj[1]);
29242 snap : function(value, inc, min){
29243 if(!inc || !value) return value;
29244 var newValue = value;
29245 var m = value % inc;
29248 newValue = value + (inc-m);
29250 newValue = value - m;
29253 return Math.max(min, newValue);
29257 resizeElement : function(){
29258 var box = this.proxy.getBox();
29259 if(this.updateBox){
29260 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29262 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29264 this.updateChildSize();
29272 constrain : function(v, diff, m, mx){
29275 }else if(v - diff > mx){
29282 onMouseMove : function(e){
29285 try{// try catch so if something goes wrong the user doesn't get hung
29287 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29291 //var curXY = this.startPoint;
29292 var curSize = this.curSize || this.startBox;
29293 var x = this.startBox.x, y = this.startBox.y;
29294 var ox = x, oy = y;
29295 var w = curSize.width, h = curSize.height;
29296 var ow = w, oh = h;
29297 var mw = this.minWidth, mh = this.minHeight;
29298 var mxw = this.maxWidth, mxh = this.maxHeight;
29299 var wi = this.widthIncrement;
29300 var hi = this.heightIncrement;
29302 var eventXY = e.getXY();
29303 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29304 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29306 var pos = this.activeHandle.position;
29311 w = Math.min(Math.max(mw, w), mxw);
29316 h = Math.min(Math.max(mh, h), mxh);
29321 w = Math.min(Math.max(mw, w), mxw);
29322 h = Math.min(Math.max(mh, h), mxh);
29325 diffY = this.constrain(h, diffY, mh, mxh);
29332 var adiffX = Math.abs(diffX);
29333 var sub = (adiffX % wi); // how much
29334 if (sub > (wi/2)) { // far enough to snap
29335 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29337 // remove difference..
29338 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29342 x = Math.max(this.minX, x);
29345 diffX = this.constrain(w, diffX, mw, mxw);
29351 w = Math.min(Math.max(mw, w), mxw);
29352 diffY = this.constrain(h, diffY, mh, mxh);
29357 diffX = this.constrain(w, diffX, mw, mxw);
29358 diffY = this.constrain(h, diffY, mh, mxh);
29365 diffX = this.constrain(w, diffX, mw, mxw);
29367 h = Math.min(Math.max(mh, h), mxh);
29373 var sw = this.snap(w, wi, mw);
29374 var sh = this.snap(h, hi, mh);
29375 if(sw != w || sh != h){
29398 if(this.preserveRatio){
29403 h = Math.min(Math.max(mh, h), mxh);
29408 w = Math.min(Math.max(mw, w), mxw);
29413 w = Math.min(Math.max(mw, w), mxw);
29419 w = Math.min(Math.max(mw, w), mxw);
29425 h = Math.min(Math.max(mh, h), mxh);
29433 h = Math.min(Math.max(mh, h), mxh);
29443 h = Math.min(Math.max(mh, h), mxh);
29451 if (pos == 'hdrag') {
29454 this.proxy.setBounds(x, y, w, h);
29456 this.resizeElement();
29460 this.fireEvent("resizing", this, x, y, w, h, e);
29464 handleOver : function(){
29466 this.el.addClass("x-resizable-over");
29471 handleOut : function(){
29472 if(!this.resizing){
29473 this.el.removeClass("x-resizable-over");
29478 * Returns the element this component is bound to.
29479 * @return {Roo.Element}
29481 getEl : function(){
29486 * Returns the resizeChild element (or null).
29487 * @return {Roo.Element}
29489 getResizeChild : function(){
29490 return this.resizeChild;
29492 groupHandler : function()
29497 * Destroys this resizable. If the element was wrapped and
29498 * removeEl is not true then the element remains.
29499 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29501 destroy : function(removeEl){
29502 this.proxy.remove();
29504 this.overlay.removeAllListeners();
29505 this.overlay.remove();
29507 var ps = Roo.Resizable.positions;
29509 if(typeof ps[k] != "function" && this[ps[k]]){
29510 var h = this[ps[k]];
29511 h.el.removeAllListeners();
29516 this.el.update("");
29523 // hash to map config positions to true positions
29524 Roo.Resizable.positions = {
29525 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29530 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29532 // only initialize the template if resizable is used
29533 var tpl = Roo.DomHelper.createTemplate(
29534 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29537 Roo.Resizable.Handle.prototype.tpl = tpl;
29539 this.position = pos;
29541 // show north drag fro topdra
29542 var handlepos = pos == 'hdrag' ? 'north' : pos;
29544 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29545 if (pos == 'hdrag') {
29546 this.el.setStyle('cursor', 'pointer');
29548 this.el.unselectable();
29550 this.el.setOpacity(0);
29552 this.el.on("mousedown", this.onMouseDown, this);
29553 if(!disableTrackOver){
29554 this.el.on("mouseover", this.onMouseOver, this);
29555 this.el.on("mouseout", this.onMouseOut, this);
29560 Roo.Resizable.Handle.prototype = {
29561 afterResize : function(rz){
29565 onMouseDown : function(e){
29566 this.rz.onMouseDown(this, e);
29569 onMouseOver : function(e){
29570 this.rz.handleOver(this, e);
29573 onMouseOut : function(e){
29574 this.rz.handleOut(this, e);
29578 * Ext JS Library 1.1.1
29579 * Copyright(c) 2006-2007, Ext JS, LLC.
29581 * Originally Released Under LGPL - original licence link has changed is not relivant.
29584 * <script type="text/javascript">
29588 * @class Roo.Editor
29589 * @extends Roo.Component
29590 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29592 * Create a new Editor
29593 * @param {Roo.form.Field} field The Field object (or descendant)
29594 * @param {Object} config The config object
29596 Roo.Editor = function(field, config){
29597 Roo.Editor.superclass.constructor.call(this, config);
29598 this.field = field;
29601 * @event beforestartedit
29602 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29603 * false from the handler of this event.
29604 * @param {Editor} this
29605 * @param {Roo.Element} boundEl The underlying element bound to this editor
29606 * @param {Mixed} value The field value being set
29608 "beforestartedit" : true,
29611 * Fires when this editor is displayed
29612 * @param {Roo.Element} boundEl The underlying element bound to this editor
29613 * @param {Mixed} value The starting field value
29615 "startedit" : true,
29617 * @event beforecomplete
29618 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29619 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29620 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29621 * event will not fire since no edit actually occurred.
29622 * @param {Editor} this
29623 * @param {Mixed} value The current field value
29624 * @param {Mixed} startValue The original field value
29626 "beforecomplete" : true,
29629 * Fires after editing is complete and any changed value has been written to the underlying field.
29630 * @param {Editor} this
29631 * @param {Mixed} value The current field value
29632 * @param {Mixed} startValue The original field value
29636 * @event specialkey
29637 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29638 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29639 * @param {Roo.form.Field} this
29640 * @param {Roo.EventObject} e The event object
29642 "specialkey" : true
29646 Roo.extend(Roo.Editor, Roo.Component, {
29648 * @cfg {Boolean/String} autosize
29649 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29650 * or "height" to adopt the height only (defaults to false)
29653 * @cfg {Boolean} revertInvalid
29654 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29655 * validation fails (defaults to true)
29658 * @cfg {Boolean} ignoreNoChange
29659 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29660 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29661 * will never be ignored.
29664 * @cfg {Boolean} hideEl
29665 * False to keep the bound element visible while the editor is displayed (defaults to true)
29668 * @cfg {Mixed} value
29669 * The data value of the underlying field (defaults to "")
29673 * @cfg {String} alignment
29674 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29678 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29679 * for bottom-right shadow (defaults to "frame")
29683 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29687 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29689 completeOnEnter : false,
29691 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29693 cancelOnEsc : false,
29695 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29700 onRender : function(ct, position){
29701 this.el = new Roo.Layer({
29702 shadow: this.shadow,
29708 constrain: this.constrain
29710 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29711 if(this.field.msgTarget != 'title'){
29712 this.field.msgTarget = 'qtip';
29714 this.field.render(this.el);
29716 this.field.el.dom.setAttribute('autocomplete', 'off');
29718 this.field.on("specialkey", this.onSpecialKey, this);
29719 if(this.swallowKeys){
29720 this.field.el.swallowEvent(['keydown','keypress']);
29723 this.field.on("blur", this.onBlur, this);
29724 if(this.field.grow){
29725 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29729 onSpecialKey : function(field, e)
29731 //Roo.log('editor onSpecialKey');
29732 if(this.completeOnEnter && e.getKey() == e.ENTER){
29734 this.completeEdit();
29737 // do not fire special key otherwise it might hide close the editor...
29738 if(e.getKey() == e.ENTER){
29741 if(this.cancelOnEsc && e.getKey() == e.ESC){
29745 this.fireEvent('specialkey', field, e);
29750 * Starts the editing process and shows the editor.
29751 * @param {String/HTMLElement/Element} el The element to edit
29752 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29753 * to the innerHTML of el.
29755 startEdit : function(el, value){
29757 this.completeEdit();
29759 this.boundEl = Roo.get(el);
29760 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29761 if(!this.rendered){
29762 this.render(this.parentEl || document.body);
29764 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29767 this.startValue = v;
29768 this.field.setValue(v);
29770 var sz = this.boundEl.getSize();
29771 switch(this.autoSize){
29773 this.setSize(sz.width, "");
29776 this.setSize("", sz.height);
29779 this.setSize(sz.width, sz.height);
29782 this.el.alignTo(this.boundEl, this.alignment);
29783 this.editing = true;
29785 Roo.QuickTips.disable();
29791 * Sets the height and width of this editor.
29792 * @param {Number} width The new width
29793 * @param {Number} height The new height
29795 setSize : function(w, h){
29796 this.field.setSize(w, h);
29803 * Realigns the editor to the bound field based on the current alignment config value.
29805 realign : function(){
29806 this.el.alignTo(this.boundEl, this.alignment);
29810 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29811 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29813 completeEdit : function(remainVisible){
29817 var v = this.getValue();
29818 if(this.revertInvalid !== false && !this.field.isValid()){
29819 v = this.startValue;
29820 this.cancelEdit(true);
29822 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29823 this.editing = false;
29827 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29828 this.editing = false;
29829 if(this.updateEl && this.boundEl){
29830 this.boundEl.update(v);
29832 if(remainVisible !== true){
29835 this.fireEvent("complete", this, v, this.startValue);
29840 onShow : function(){
29842 if(this.hideEl !== false){
29843 this.boundEl.hide();
29846 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29847 this.fixIEFocus = true;
29848 this.deferredFocus.defer(50, this);
29850 this.field.focus();
29852 this.fireEvent("startedit", this.boundEl, this.startValue);
29855 deferredFocus : function(){
29857 this.field.focus();
29862 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29863 * reverted to the original starting value.
29864 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29865 * cancel (defaults to false)
29867 cancelEdit : function(remainVisible){
29869 this.setValue(this.startValue);
29870 if(remainVisible !== true){
29877 onBlur : function(){
29878 if(this.allowBlur !== true && this.editing){
29879 this.completeEdit();
29884 onHide : function(){
29886 this.completeEdit();
29890 if(this.field.collapse){
29891 this.field.collapse();
29894 if(this.hideEl !== false){
29895 this.boundEl.show();
29898 Roo.QuickTips.enable();
29903 * Sets the data value of the editor
29904 * @param {Mixed} value Any valid value supported by the underlying field
29906 setValue : function(v){
29907 this.field.setValue(v);
29911 * Gets the data value of the editor
29912 * @return {Mixed} The data value
29914 getValue : function(){
29915 return this.field.getValue();
29919 * Ext JS Library 1.1.1
29920 * Copyright(c) 2006-2007, Ext JS, LLC.
29922 * Originally Released Under LGPL - original licence link has changed is not relivant.
29925 * <script type="text/javascript">
29929 * @class Roo.BasicDialog
29930 * @extends Roo.util.Observable
29931 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29933 var dlg = new Roo.BasicDialog("my-dlg", {
29942 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
29943 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
29944 dlg.addButton('Cancel', dlg.hide, dlg);
29947 <b>A Dialog should always be a direct child of the body element.</b>
29948 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
29949 * @cfg {String} title Default text to display in the title bar (defaults to null)
29950 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29951 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29952 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
29953 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
29954 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
29955 * (defaults to null with no animation)
29956 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
29957 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
29958 * property for valid values (defaults to 'all')
29959 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
29960 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
29961 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
29962 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
29963 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
29964 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
29965 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
29966 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
29967 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
29968 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
29969 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
29970 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
29971 * draggable = true (defaults to false)
29972 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
29973 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
29974 * shadow (defaults to false)
29975 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
29976 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
29977 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
29978 * @cfg {Array} buttons Array of buttons
29979 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
29981 * Create a new BasicDialog.
29982 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
29983 * @param {Object} config Configuration options
29985 Roo.BasicDialog = function(el, config){
29986 this.el = Roo.get(el);
29987 var dh = Roo.DomHelper;
29988 if(!this.el && config && config.autoCreate){
29989 if(typeof config.autoCreate == "object"){
29990 if(!config.autoCreate.id){
29991 config.autoCreate.id = el;
29993 this.el = dh.append(document.body,
29994 config.autoCreate, true);
29996 this.el = dh.append(document.body,
29997 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30001 el.setDisplayed(true);
30002 el.hide = this.hideAction;
30004 el.addClass("x-dlg");
30006 Roo.apply(this, config);
30008 this.proxy = el.createProxy("x-dlg-proxy");
30009 this.proxy.hide = this.hideAction;
30010 this.proxy.setOpacity(.5);
30014 el.setWidth(config.width);
30017 el.setHeight(config.height);
30019 this.size = el.getSize();
30020 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30021 this.xy = [config.x,config.y];
30023 this.xy = el.getCenterXY(true);
30025 /** The header element @type Roo.Element */
30026 this.header = el.child("> .x-dlg-hd");
30027 /** The body element @type Roo.Element */
30028 this.body = el.child("> .x-dlg-bd");
30029 /** The footer element @type Roo.Element */
30030 this.footer = el.child("> .x-dlg-ft");
30033 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30036 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30039 this.header.unselectable();
30041 this.header.update(this.title);
30043 // this element allows the dialog to be focused for keyboard event
30044 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30045 this.focusEl.swallowEvent("click", true);
30047 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30049 // wrap the body and footer for special rendering
30050 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30052 this.bwrap.dom.appendChild(this.footer.dom);
30055 this.bg = this.el.createChild({
30056 tag: "div", cls:"x-dlg-bg",
30057 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30059 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30062 if(this.autoScroll !== false && !this.autoTabs){
30063 this.body.setStyle("overflow", "auto");
30066 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30068 if(this.closable !== false){
30069 this.el.addClass("x-dlg-closable");
30070 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30071 this.close.on("click", this.closeClick, this);
30072 this.close.addClassOnOver("x-dlg-close-over");
30074 if(this.collapsible !== false){
30075 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30076 this.collapseBtn.on("click", this.collapseClick, this);
30077 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30078 this.header.on("dblclick", this.collapseClick, this);
30080 if(this.resizable !== false){
30081 this.el.addClass("x-dlg-resizable");
30082 this.resizer = new Roo.Resizable(el, {
30083 minWidth: this.minWidth || 80,
30084 minHeight:this.minHeight || 80,
30085 handles: this.resizeHandles || "all",
30088 this.resizer.on("beforeresize", this.beforeResize, this);
30089 this.resizer.on("resize", this.onResize, this);
30091 if(this.draggable !== false){
30092 el.addClass("x-dlg-draggable");
30093 if (!this.proxyDrag) {
30094 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30097 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30099 dd.setHandleElId(this.header.id);
30100 dd.endDrag = this.endMove.createDelegate(this);
30101 dd.startDrag = this.startMove.createDelegate(this);
30102 dd.onDrag = this.onDrag.createDelegate(this);
30107 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30108 this.mask.enableDisplayMode("block");
30110 this.el.addClass("x-dlg-modal");
30113 this.shadow = new Roo.Shadow({
30114 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30115 offset : this.shadowOffset
30118 this.shadowOffset = 0;
30120 if(Roo.useShims && this.shim !== false){
30121 this.shim = this.el.createShim();
30122 this.shim.hide = this.hideAction;
30130 if (this.buttons) {
30131 var bts= this.buttons;
30133 Roo.each(bts, function(b) {
30142 * Fires when a key is pressed
30143 * @param {Roo.BasicDialog} this
30144 * @param {Roo.EventObject} e
30149 * Fires when this dialog is moved by the user.
30150 * @param {Roo.BasicDialog} this
30151 * @param {Number} x The new page X
30152 * @param {Number} y The new page Y
30157 * Fires when this dialog is resized by the user.
30158 * @param {Roo.BasicDialog} this
30159 * @param {Number} width The new width
30160 * @param {Number} height The new height
30164 * @event beforehide
30165 * Fires before this dialog is hidden.
30166 * @param {Roo.BasicDialog} this
30168 "beforehide" : true,
30171 * Fires when this dialog is hidden.
30172 * @param {Roo.BasicDialog} this
30176 * @event beforeshow
30177 * Fires before this dialog is shown.
30178 * @param {Roo.BasicDialog} this
30180 "beforeshow" : true,
30183 * Fires when this dialog is shown.
30184 * @param {Roo.BasicDialog} this
30188 el.on("keydown", this.onKeyDown, this);
30189 el.on("mousedown", this.toFront, this);
30190 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30192 Roo.DialogManager.register(this);
30193 Roo.BasicDialog.superclass.constructor.call(this);
30196 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30197 shadowOffset: Roo.isIE ? 6 : 5,
30200 minButtonWidth: 75,
30201 defaultButton: null,
30202 buttonAlign: "right",
30207 * Sets the dialog title text
30208 * @param {String} text The title text to display
30209 * @return {Roo.BasicDialog} this
30211 setTitle : function(text){
30212 this.header.update(text);
30217 closeClick : function(){
30222 collapseClick : function(){
30223 this[this.collapsed ? "expand" : "collapse"]();
30227 * Collapses the dialog to its minimized state (only the title bar is visible).
30228 * Equivalent to the user clicking the collapse dialog button.
30230 collapse : function(){
30231 if(!this.collapsed){
30232 this.collapsed = true;
30233 this.el.addClass("x-dlg-collapsed");
30234 this.restoreHeight = this.el.getHeight();
30235 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30240 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30241 * clicking the expand dialog button.
30243 expand : function(){
30244 if(this.collapsed){
30245 this.collapsed = false;
30246 this.el.removeClass("x-dlg-collapsed");
30247 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30252 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30253 * @return {Roo.TabPanel} The tabs component
30255 initTabs : function(){
30256 var tabs = this.getTabs();
30257 while(tabs.getTab(0)){
30260 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30262 tabs.addTab(Roo.id(dom), dom.title);
30270 beforeResize : function(){
30271 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30275 onResize : function(){
30276 this.refreshSize();
30277 this.syncBodyHeight();
30278 this.adjustAssets();
30280 this.fireEvent("resize", this, this.size.width, this.size.height);
30284 onKeyDown : function(e){
30285 if(this.isVisible()){
30286 this.fireEvent("keydown", this, e);
30291 * Resizes the dialog.
30292 * @param {Number} width
30293 * @param {Number} height
30294 * @return {Roo.BasicDialog} this
30296 resizeTo : function(width, height){
30297 this.el.setSize(width, height);
30298 this.size = {width: width, height: height};
30299 this.syncBodyHeight();
30300 if(this.fixedcenter){
30303 if(this.isVisible()){
30304 this.constrainXY();
30305 this.adjustAssets();
30307 this.fireEvent("resize", this, width, height);
30313 * Resizes the dialog to fit the specified content size.
30314 * @param {Number} width
30315 * @param {Number} height
30316 * @return {Roo.BasicDialog} this
30318 setContentSize : function(w, h){
30319 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30320 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30321 //if(!this.el.isBorderBox()){
30322 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30323 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30326 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30327 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30329 this.resizeTo(w, h);
30334 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30335 * executed in response to a particular key being pressed while the dialog is active.
30336 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30337 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30338 * @param {Function} fn The function to call
30339 * @param {Object} scope (optional) The scope of the function
30340 * @return {Roo.BasicDialog} this
30342 addKeyListener : function(key, fn, scope){
30343 var keyCode, shift, ctrl, alt;
30344 if(typeof key == "object" && !(key instanceof Array)){
30345 keyCode = key["key"];
30346 shift = key["shift"];
30347 ctrl = key["ctrl"];
30352 var handler = function(dlg, e){
30353 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30354 var k = e.getKey();
30355 if(keyCode instanceof Array){
30356 for(var i = 0, len = keyCode.length; i < len; i++){
30357 if(keyCode[i] == k){
30358 fn.call(scope || window, dlg, k, e);
30364 fn.call(scope || window, dlg, k, e);
30369 this.on("keydown", handler);
30374 * Returns the TabPanel component (creates it if it doesn't exist).
30375 * Note: If you wish to simply check for the existence of tabs without creating them,
30376 * check for a null 'tabs' property.
30377 * @return {Roo.TabPanel} The tabs component
30379 getTabs : function(){
30381 this.el.addClass("x-dlg-auto-tabs");
30382 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30383 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30389 * Adds a button to the footer section of the dialog.
30390 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30391 * object or a valid Roo.DomHelper element config
30392 * @param {Function} handler The function called when the button is clicked
30393 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30394 * @return {Roo.Button} The new button
30396 addButton : function(config, handler, scope){
30397 var dh = Roo.DomHelper;
30399 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30401 if(!this.btnContainer){
30402 var tb = this.footer.createChild({
30404 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30405 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30407 this.btnContainer = tb.firstChild.firstChild.firstChild;
30412 minWidth: this.minButtonWidth,
30415 if(typeof config == "string"){
30416 bconfig.text = config;
30419 bconfig.dhconfig = config;
30421 Roo.apply(bconfig, config);
30425 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30426 bconfig.position = Math.max(0, bconfig.position);
30427 fc = this.btnContainer.childNodes[bconfig.position];
30430 var btn = new Roo.Button(
30432 this.btnContainer.insertBefore(document.createElement("td"),fc)
30433 : this.btnContainer.appendChild(document.createElement("td")),
30434 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30437 this.syncBodyHeight();
30440 * Array of all the buttons that have been added to this dialog via addButton
30445 this.buttons.push(btn);
30450 * Sets the default button to be focused when the dialog is displayed.
30451 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30452 * @return {Roo.BasicDialog} this
30454 setDefaultButton : function(btn){
30455 this.defaultButton = btn;
30460 getHeaderFooterHeight : function(safe){
30463 height += this.header.getHeight();
30466 var fm = this.footer.getMargins();
30467 height += (this.footer.getHeight()+fm.top+fm.bottom);
30469 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30470 height += this.centerBg.getPadding("tb");
30475 syncBodyHeight : function()
30477 var bd = this.body, // the text
30478 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30480 var height = this.size.height - this.getHeaderFooterHeight(false);
30481 bd.setHeight(height-bd.getMargins("tb"));
30482 var hh = this.header.getHeight();
30483 var h = this.size.height-hh;
30486 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30487 bw.setHeight(h-cb.getPadding("tb"));
30489 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30490 bd.setWidth(bw.getWidth(true));
30492 this.tabs.syncHeight();
30494 this.tabs.el.repaint();
30500 * Restores the previous state of the dialog if Roo.state is configured.
30501 * @return {Roo.BasicDialog} this
30503 restoreState : function(){
30504 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30505 if(box && box.width){
30506 this.xy = [box.x, box.y];
30507 this.resizeTo(box.width, box.height);
30513 beforeShow : function(){
30515 if(this.fixedcenter){
30516 this.xy = this.el.getCenterXY(true);
30519 Roo.get(document.body).addClass("x-body-masked");
30520 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30523 this.constrainXY();
30527 animShow : function(){
30528 var b = Roo.get(this.animateTarget).getBox();
30529 this.proxy.setSize(b.width, b.height);
30530 this.proxy.setLocation(b.x, b.y);
30532 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30533 true, .35, this.showEl.createDelegate(this));
30537 * Shows the dialog.
30538 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30539 * @return {Roo.BasicDialog} this
30541 show : function(animateTarget){
30542 if (this.fireEvent("beforeshow", this) === false){
30545 if(this.syncHeightBeforeShow){
30546 this.syncBodyHeight();
30547 }else if(this.firstShow){
30548 this.firstShow = false;
30549 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30551 this.animateTarget = animateTarget || this.animateTarget;
30552 if(!this.el.isVisible()){
30554 if(this.animateTarget && Roo.get(this.animateTarget)){
30564 showEl : function(){
30566 this.el.setXY(this.xy);
30568 this.adjustAssets(true);
30571 // IE peekaboo bug - fix found by Dave Fenwick
30575 this.fireEvent("show", this);
30579 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30580 * dialog itself will receive focus.
30582 focus : function(){
30583 if(this.defaultButton){
30584 this.defaultButton.focus();
30586 this.focusEl.focus();
30591 constrainXY : function(){
30592 if(this.constraintoviewport !== false){
30593 if(!this.viewSize){
30594 if(this.container){
30595 var s = this.container.getSize();
30596 this.viewSize = [s.width, s.height];
30598 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30601 var s = Roo.get(this.container||document).getScroll();
30603 var x = this.xy[0], y = this.xy[1];
30604 var w = this.size.width, h = this.size.height;
30605 var vw = this.viewSize[0], vh = this.viewSize[1];
30606 // only move it if it needs it
30608 // first validate right/bottom
30609 if(x + w > vw+s.left){
30613 if(y + h > vh+s.top){
30617 // then make sure top/left isn't negative
30629 if(this.isVisible()){
30630 this.el.setLocation(x, y);
30631 this.adjustAssets();
30638 onDrag : function(){
30639 if(!this.proxyDrag){
30640 this.xy = this.el.getXY();
30641 this.adjustAssets();
30646 adjustAssets : function(doShow){
30647 var x = this.xy[0], y = this.xy[1];
30648 var w = this.size.width, h = this.size.height;
30649 if(doShow === true){
30651 this.shadow.show(this.el);
30657 if(this.shadow && this.shadow.isVisible()){
30658 this.shadow.show(this.el);
30660 if(this.shim && this.shim.isVisible()){
30661 this.shim.setBounds(x, y, w, h);
30666 adjustViewport : function(w, h){
30668 w = Roo.lib.Dom.getViewWidth();
30669 h = Roo.lib.Dom.getViewHeight();
30672 this.viewSize = [w, h];
30673 if(this.modal && this.mask.isVisible()){
30674 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30675 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30677 if(this.isVisible()){
30678 this.constrainXY();
30683 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30684 * shadow, proxy, mask, etc.) Also removes all event listeners.
30685 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30687 destroy : function(removeEl){
30688 if(this.isVisible()){
30689 this.animateTarget = null;
30692 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30694 this.tabs.destroy(removeEl);
30707 for(var i = 0, len = this.buttons.length; i < len; i++){
30708 this.buttons[i].destroy();
30711 this.el.removeAllListeners();
30712 if(removeEl === true){
30713 this.el.update("");
30716 Roo.DialogManager.unregister(this);
30720 startMove : function(){
30721 if(this.proxyDrag){
30724 if(this.constraintoviewport !== false){
30725 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30730 endMove : function(){
30731 if(!this.proxyDrag){
30732 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30734 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30737 this.refreshSize();
30738 this.adjustAssets();
30740 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30744 * Brings this dialog to the front of any other visible dialogs
30745 * @return {Roo.BasicDialog} this
30747 toFront : function(){
30748 Roo.DialogManager.bringToFront(this);
30753 * Sends this dialog to the back (under) of any other visible dialogs
30754 * @return {Roo.BasicDialog} this
30756 toBack : function(){
30757 Roo.DialogManager.sendToBack(this);
30762 * Centers this dialog in the viewport
30763 * @return {Roo.BasicDialog} this
30765 center : function(){
30766 var xy = this.el.getCenterXY(true);
30767 this.moveTo(xy[0], xy[1]);
30772 * Moves the dialog's top-left corner to the specified point
30773 * @param {Number} x
30774 * @param {Number} y
30775 * @return {Roo.BasicDialog} this
30777 moveTo : function(x, y){
30779 if(this.isVisible()){
30780 this.el.setXY(this.xy);
30781 this.adjustAssets();
30787 * Aligns the dialog to the specified element
30788 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30789 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30790 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30791 * @return {Roo.BasicDialog} this
30793 alignTo : function(element, position, offsets){
30794 this.xy = this.el.getAlignToXY(element, position, offsets);
30795 if(this.isVisible()){
30796 this.el.setXY(this.xy);
30797 this.adjustAssets();
30803 * Anchors an element to another element and realigns it when the window is resized.
30804 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30805 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30806 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30807 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30808 * is a number, it is used as the buffer delay (defaults to 50ms).
30809 * @return {Roo.BasicDialog} this
30811 anchorTo : function(el, alignment, offsets, monitorScroll){
30812 var action = function(){
30813 this.alignTo(el, alignment, offsets);
30815 Roo.EventManager.onWindowResize(action, this);
30816 var tm = typeof monitorScroll;
30817 if(tm != 'undefined'){
30818 Roo.EventManager.on(window, 'scroll', action, this,
30819 {buffer: tm == 'number' ? monitorScroll : 50});
30826 * Returns true if the dialog is visible
30827 * @return {Boolean}
30829 isVisible : function(){
30830 return this.el.isVisible();
30834 animHide : function(callback){
30835 var b = Roo.get(this.animateTarget).getBox();
30837 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30839 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30840 this.hideEl.createDelegate(this, [callback]));
30844 * Hides the dialog.
30845 * @param {Function} callback (optional) Function to call when the dialog is hidden
30846 * @return {Roo.BasicDialog} this
30848 hide : function(callback){
30849 if (this.fireEvent("beforehide", this) === false){
30853 this.shadow.hide();
30858 // sometimes animateTarget seems to get set.. causing problems...
30859 // this just double checks..
30860 if(this.animateTarget && Roo.get(this.animateTarget)) {
30861 this.animHide(callback);
30864 this.hideEl(callback);
30870 hideEl : function(callback){
30874 Roo.get(document.body).removeClass("x-body-masked");
30876 this.fireEvent("hide", this);
30877 if(typeof callback == "function"){
30883 hideAction : function(){
30884 this.setLeft("-10000px");
30885 this.setTop("-10000px");
30886 this.setStyle("visibility", "hidden");
30890 refreshSize : function(){
30891 this.size = this.el.getSize();
30892 this.xy = this.el.getXY();
30893 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30897 // z-index is managed by the DialogManager and may be overwritten at any time
30898 setZIndex : function(index){
30900 this.mask.setStyle("z-index", index);
30903 this.shim.setStyle("z-index", ++index);
30906 this.shadow.setZIndex(++index);
30908 this.el.setStyle("z-index", ++index);
30910 this.proxy.setStyle("z-index", ++index);
30913 this.resizer.proxy.setStyle("z-index", ++index);
30916 this.lastZIndex = index;
30920 * Returns the element for this dialog
30921 * @return {Roo.Element} The underlying dialog Element
30923 getEl : function(){
30929 * @class Roo.DialogManager
30930 * Provides global access to BasicDialogs that have been created and
30931 * support for z-indexing (layering) multiple open dialogs.
30933 Roo.DialogManager = function(){
30935 var accessList = [];
30939 var sortDialogs = function(d1, d2){
30940 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
30944 var orderDialogs = function(){
30945 accessList.sort(sortDialogs);
30946 var seed = Roo.DialogManager.zseed;
30947 for(var i = 0, len = accessList.length; i < len; i++){
30948 var dlg = accessList[i];
30950 dlg.setZIndex(seed + (i*10));
30957 * The starting z-index for BasicDialogs (defaults to 9000)
30958 * @type Number The z-index value
30963 register : function(dlg){
30964 list[dlg.id] = dlg;
30965 accessList.push(dlg);
30969 unregister : function(dlg){
30970 delete list[dlg.id];
30973 if(!accessList.indexOf){
30974 for( i = 0, len = accessList.length; i < len; i++){
30975 if(accessList[i] == dlg){
30976 accessList.splice(i, 1);
30981 i = accessList.indexOf(dlg);
30983 accessList.splice(i, 1);
30989 * Gets a registered dialog by id
30990 * @param {String/Object} id The id of the dialog or a dialog
30991 * @return {Roo.BasicDialog} this
30993 get : function(id){
30994 return typeof id == "object" ? id : list[id];
30998 * Brings the specified dialog to the front
30999 * @param {String/Object} dlg The id of the dialog or a dialog
31000 * @return {Roo.BasicDialog} this
31002 bringToFront : function(dlg){
31003 dlg = this.get(dlg);
31006 dlg._lastAccess = new Date().getTime();
31013 * Sends the specified dialog to the back
31014 * @param {String/Object} dlg The id of the dialog or a dialog
31015 * @return {Roo.BasicDialog} this
31017 sendToBack : function(dlg){
31018 dlg = this.get(dlg);
31019 dlg._lastAccess = -(new Date().getTime());
31025 * Hides all dialogs
31027 hideAll : function(){
31028 for(var id in list){
31029 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31038 * @class Roo.LayoutDialog
31039 * @extends Roo.BasicDialog
31040 * Dialog which provides adjustments for working with a layout in a Dialog.
31041 * Add your necessary layout config options to the dialog's config.<br>
31042 * Example usage (including a nested layout):
31045 dialog = new Roo.LayoutDialog("download-dlg", {
31054 // layout config merges with the dialog config
31056 tabPosition: "top",
31057 alwaysShowTabs: true
31060 dialog.addKeyListener(27, dialog.hide, dialog);
31061 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31062 dialog.addButton("Build It!", this.getDownload, this);
31064 // we can even add nested layouts
31065 var innerLayout = new Roo.BorderLayout("dl-inner", {
31075 innerLayout.beginUpdate();
31076 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31077 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31078 innerLayout.endUpdate(true);
31080 var layout = dialog.getLayout();
31081 layout.beginUpdate();
31082 layout.add("center", new Roo.ContentPanel("standard-panel",
31083 {title: "Download the Source", fitToFrame:true}));
31084 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31085 {title: "Build your own roo.js"}));
31086 layout.getRegion("center").showPanel(sp);
31087 layout.endUpdate();
31091 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31092 * @param {Object} config configuration options
31094 Roo.LayoutDialog = function(el, cfg){
31097 if (typeof(cfg) == 'undefined') {
31098 config = Roo.apply({}, el);
31099 // not sure why we use documentElement here.. - it should always be body.
31100 // IE7 borks horribly if we use documentElement.
31101 // webkit also does not like documentElement - it creates a body element...
31102 el = Roo.get( document.body || document.documentElement ).createChild();
31103 //config.autoCreate = true;
31107 config.autoTabs = false;
31108 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31109 this.body.setStyle({overflow:"hidden", position:"relative"});
31110 this.layout = new Roo.BorderLayout(this.body.dom, config);
31111 this.layout.monitorWindowResize = false;
31112 this.el.addClass("x-dlg-auto-layout");
31113 // fix case when center region overwrites center function
31114 this.center = Roo.BasicDialog.prototype.center;
31115 this.on("show", this.layout.layout, this.layout, true);
31116 if (config.items) {
31117 var xitems = config.items;
31118 delete config.items;
31119 Roo.each(xitems, this.addxtype, this);
31124 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31126 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31129 endUpdate : function(){
31130 this.layout.endUpdate();
31134 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31137 beginUpdate : function(){
31138 this.layout.beginUpdate();
31142 * Get the BorderLayout for this dialog
31143 * @return {Roo.BorderLayout}
31145 getLayout : function(){
31146 return this.layout;
31149 showEl : function(){
31150 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31152 this.layout.layout();
31157 // Use the syncHeightBeforeShow config option to control this automatically
31158 syncBodyHeight : function(){
31159 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31160 if(this.layout){this.layout.layout();}
31164 * Add an xtype element (actually adds to the layout.)
31165 * @return {Object} xdata xtype object data.
31168 addxtype : function(c) {
31169 return this.layout.addxtype(c);
31173 * Ext JS Library 1.1.1
31174 * Copyright(c) 2006-2007, Ext JS, LLC.
31176 * Originally Released Under LGPL - original licence link has changed is not relivant.
31179 * <script type="text/javascript">
31183 * @class Roo.MessageBox
31184 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31188 Roo.Msg.alert('Status', 'Changes saved successfully.');
31190 // Prompt for user data:
31191 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31193 // process text value...
31197 // Show a dialog using config options:
31199 title:'Save Changes?',
31200 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31201 buttons: Roo.Msg.YESNOCANCEL,
31208 Roo.MessageBox = function(){
31209 var dlg, opt, mask, waitTimer;
31210 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31211 var buttons, activeTextEl, bwidth;
31214 var handleButton = function(button){
31216 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31220 var handleHide = function(){
31221 if(opt && opt.cls){
31222 dlg.el.removeClass(opt.cls);
31225 Roo.TaskMgr.stop(waitTimer);
31231 var updateButtons = function(b){
31234 buttons["ok"].hide();
31235 buttons["cancel"].hide();
31236 buttons["yes"].hide();
31237 buttons["no"].hide();
31238 dlg.footer.dom.style.display = 'none';
31241 dlg.footer.dom.style.display = '';
31242 for(var k in buttons){
31243 if(typeof buttons[k] != "function"){
31246 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31247 width += buttons[k].el.getWidth()+15;
31257 var handleEsc = function(d, k, e){
31258 if(opt && opt.closable !== false){
31268 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31269 * @return {Roo.BasicDialog} The BasicDialog element
31271 getDialog : function(){
31273 dlg = new Roo.BasicDialog("x-msg-box", {
31278 constraintoviewport:false,
31280 collapsible : false,
31283 width:400, height:100,
31284 buttonAlign:"center",
31285 closeClick : function(){
31286 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31287 handleButton("no");
31289 handleButton("cancel");
31293 dlg.on("hide", handleHide);
31295 dlg.addKeyListener(27, handleEsc);
31297 var bt = this.buttonText;
31298 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31299 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31300 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31301 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31302 bodyEl = dlg.body.createChild({
31304 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>'
31306 msgEl = bodyEl.dom.firstChild;
31307 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31308 textboxEl.enableDisplayMode();
31309 textboxEl.addKeyListener([10,13], function(){
31310 if(dlg.isVisible() && opt && opt.buttons){
31311 if(opt.buttons.ok){
31312 handleButton("ok");
31313 }else if(opt.buttons.yes){
31314 handleButton("yes");
31318 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31319 textareaEl.enableDisplayMode();
31320 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31321 progressEl.enableDisplayMode();
31322 var pf = progressEl.dom.firstChild;
31324 pp = Roo.get(pf.firstChild);
31325 pp.setHeight(pf.offsetHeight);
31333 * Updates the message box body text
31334 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31335 * the XHTML-compliant non-breaking space character '&#160;')
31336 * @return {Roo.MessageBox} This message box
31338 updateText : function(text){
31339 if(!dlg.isVisible() && !opt.width){
31340 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31342 msgEl.innerHTML = text || ' ';
31344 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31345 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31347 Math.min(opt.width || cw , this.maxWidth),
31348 Math.max(opt.minWidth || this.minWidth, bwidth)
31351 activeTextEl.setWidth(w);
31353 if(dlg.isVisible()){
31354 dlg.fixedcenter = false;
31356 // to big, make it scroll. = But as usual stupid IE does not support
31359 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31360 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31361 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31363 bodyEl.dom.style.height = '';
31364 bodyEl.dom.style.overflowY = '';
31367 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31369 bodyEl.dom.style.overflowX = '';
31372 dlg.setContentSize(w, bodyEl.getHeight());
31373 if(dlg.isVisible()){
31374 dlg.fixedcenter = true;
31380 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31381 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31382 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31383 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31384 * @return {Roo.MessageBox} This message box
31386 updateProgress : function(value, text){
31388 this.updateText(text);
31390 if (pp) { // weird bug on my firefox - for some reason this is not defined
31391 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31397 * Returns true if the message box is currently displayed
31398 * @return {Boolean} True if the message box is visible, else false
31400 isVisible : function(){
31401 return dlg && dlg.isVisible();
31405 * Hides the message box if it is displayed
31408 if(this.isVisible()){
31414 * Displays a new message box, or reinitializes an existing message box, based on the config options
31415 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31416 * The following config object properties are supported:
31418 Property Type Description
31419 ---------- --------------- ------------------------------------------------------------------------------------
31420 animEl String/Element An id or Element from which the message box should animate as it opens and
31421 closes (defaults to undefined)
31422 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31423 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31424 closable Boolean False to hide the top-right close button (defaults to true). Note that
31425 progress and wait dialogs will ignore this property and always hide the
31426 close button as they can only be closed programmatically.
31427 cls String A custom CSS class to apply to the message box element
31428 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31429 displayed (defaults to 75)
31430 fn Function A callback function to execute after closing the dialog. The arguments to the
31431 function will be btn (the name of the button that was clicked, if applicable,
31432 e.g. "ok"), and text (the value of the active text field, if applicable).
31433 Progress and wait dialogs will ignore this option since they do not respond to
31434 user actions and can only be closed programmatically, so any required function
31435 should be called by the same code after it closes the dialog.
31436 icon String A CSS class that provides a background image to be used as an icon for
31437 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31438 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31439 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31440 modal Boolean False to allow user interaction with the page while the message box is
31441 displayed (defaults to true)
31442 msg String A string that will replace the existing message box body text (defaults
31443 to the XHTML-compliant non-breaking space character ' ')
31444 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31445 progress Boolean True to display a progress bar (defaults to false)
31446 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31447 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31448 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31449 title String The title text
31450 value String The string value to set into the active textbox element if displayed
31451 wait Boolean True to display a progress bar (defaults to false)
31452 width Number The width of the dialog in pixels
31459 msg: 'Please enter your address:',
31461 buttons: Roo.MessageBox.OKCANCEL,
31464 animEl: 'addAddressBtn'
31467 * @param {Object} config Configuration options
31468 * @return {Roo.MessageBox} This message box
31470 show : function(options)
31473 // this causes nightmares if you show one dialog after another
31474 // especially on callbacks..
31476 if(this.isVisible()){
31479 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31480 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31481 Roo.log("New Dialog Message:" + options.msg )
31482 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31483 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31486 var d = this.getDialog();
31488 d.setTitle(opt.title || " ");
31489 d.close.setDisplayed(opt.closable !== false);
31490 activeTextEl = textboxEl;
31491 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31496 textareaEl.setHeight(typeof opt.multiline == "number" ?
31497 opt.multiline : this.defaultTextHeight);
31498 activeTextEl = textareaEl;
31507 progressEl.setDisplayed(opt.progress === true);
31508 this.updateProgress(0);
31509 activeTextEl.dom.value = opt.value || "";
31511 dlg.setDefaultButton(activeTextEl);
31513 var bs = opt.buttons;
31516 db = buttons["ok"];
31517 }else if(bs && bs.yes){
31518 db = buttons["yes"];
31520 dlg.setDefaultButton(db);
31522 bwidth = updateButtons(opt.buttons);
31523 this.updateText(opt.msg);
31525 d.el.addClass(opt.cls);
31527 d.proxyDrag = opt.proxyDrag === true;
31528 d.modal = opt.modal !== false;
31529 d.mask = opt.modal !== false ? mask : false;
31530 if(!d.isVisible()){
31531 // force it to the end of the z-index stack so it gets a cursor in FF
31532 document.body.appendChild(dlg.el.dom);
31533 d.animateTarget = null;
31534 d.show(options.animEl);
31540 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31541 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31542 * and closing the message box when the process is complete.
31543 * @param {String} title The title bar text
31544 * @param {String} msg The message box body text
31545 * @return {Roo.MessageBox} This message box
31547 progress : function(title, msg){
31554 minWidth: this.minProgressWidth,
31561 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31562 * If a callback function is passed it will be called after the user clicks the button, and the
31563 * id of the button that was clicked will be passed as the only parameter to the callback
31564 * (could also be the top-right close button).
31565 * @param {String} title The title bar text
31566 * @param {String} msg The message box body text
31567 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31568 * @param {Object} scope (optional) The scope of the callback function
31569 * @return {Roo.MessageBox} This message box
31571 alert : function(title, msg, fn, scope){
31584 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31585 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31586 * You are responsible for closing the message box when the process is complete.
31587 * @param {String} msg The message box body text
31588 * @param {String} title (optional) The title bar text
31589 * @return {Roo.MessageBox} This message box
31591 wait : function(msg, title){
31602 waitTimer = Roo.TaskMgr.start({
31604 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31612 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31613 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31614 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31615 * @param {String} title The title bar text
31616 * @param {String} msg The message box body text
31617 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31618 * @param {Object} scope (optional) The scope of the callback function
31619 * @return {Roo.MessageBox} This message box
31621 confirm : function(title, msg, fn, scope){
31625 buttons: this.YESNO,
31634 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31635 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31636 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31637 * (could also be the top-right close button) and the text that was entered will be passed as the two
31638 * parameters to the callback.
31639 * @param {String} title The title bar text
31640 * @param {String} msg The message box body text
31641 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31642 * @param {Object} scope (optional) The scope of the callback function
31643 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31644 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31645 * @return {Roo.MessageBox} This message box
31647 prompt : function(title, msg, fn, scope, multiline){
31651 buttons: this.OKCANCEL,
31656 multiline: multiline,
31663 * Button config that displays a single OK button
31668 * Button config that displays Yes and No buttons
31671 YESNO : {yes:true, no:true},
31673 * Button config that displays OK and Cancel buttons
31676 OKCANCEL : {ok:true, cancel:true},
31678 * Button config that displays Yes, No and Cancel buttons
31681 YESNOCANCEL : {yes:true, no:true, cancel:true},
31684 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31687 defaultTextHeight : 75,
31689 * The maximum width in pixels of the message box (defaults to 600)
31694 * The minimum width in pixels of the message box (defaults to 100)
31699 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31700 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31703 minProgressWidth : 250,
31705 * An object containing the default button text strings that can be overriden for localized language support.
31706 * Supported properties are: ok, cancel, yes and no.
31707 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31720 * Shorthand for {@link Roo.MessageBox}
31722 Roo.Msg = Roo.MessageBox;/*
31724 * Ext JS Library 1.1.1
31725 * Copyright(c) 2006-2007, Ext JS, LLC.
31727 * Originally Released Under LGPL - original licence link has changed is not relivant.
31730 * <script type="text/javascript">
31733 * @class Roo.QuickTips
31734 * Provides attractive and customizable tooltips for any element.
31737 Roo.QuickTips = function(){
31738 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31739 var ce, bd, xy, dd;
31740 var visible = false, disabled = true, inited = false;
31741 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31743 var onOver = function(e){
31747 var t = e.getTarget();
31748 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31751 if(ce && t == ce.el){
31752 clearTimeout(hideProc);
31755 if(t && tagEls[t.id]){
31756 tagEls[t.id].el = t;
31757 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31760 var ttp, et = Roo.fly(t);
31761 var ns = cfg.namespace;
31762 if(tm.interceptTitles && t.title){
31765 t.removeAttribute("title");
31766 e.preventDefault();
31768 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31771 showProc = show.defer(tm.showDelay, tm, [{
31774 width: et.getAttributeNS(ns, cfg.width),
31775 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31776 title: et.getAttributeNS(ns, cfg.title),
31777 cls: et.getAttributeNS(ns, cfg.cls)
31782 var onOut = function(e){
31783 clearTimeout(showProc);
31784 var t = e.getTarget();
31785 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31786 hideProc = setTimeout(hide, tm.hideDelay);
31790 var onMove = function(e){
31796 if(tm.trackMouse && ce){
31801 var onDown = function(e){
31802 clearTimeout(showProc);
31803 clearTimeout(hideProc);
31805 if(tm.hideOnClick){
31808 tm.enable.defer(100, tm);
31813 var getPad = function(){
31814 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31817 var show = function(o){
31821 clearTimeout(dismissProc);
31823 if(removeCls){ // in case manually hidden
31824 el.removeClass(removeCls);
31828 el.addClass(ce.cls);
31829 removeCls = ce.cls;
31832 tipTitle.update(ce.title);
31835 tipTitle.update('');
31838 el.dom.style.width = tm.maxWidth+'px';
31839 //tipBody.dom.style.width = '';
31840 tipBodyText.update(o.text);
31841 var p = getPad(), w = ce.width;
31843 var td = tipBodyText.dom;
31844 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31845 if(aw > tm.maxWidth){
31847 }else if(aw < tm.minWidth){
31853 //tipBody.setWidth(w);
31854 el.setWidth(parseInt(w, 10) + p);
31855 if(ce.autoHide === false){
31856 close.setDisplayed(true);
31861 close.setDisplayed(false);
31867 el.avoidY = xy[1]-18;
31872 el.setStyle("visibility", "visible");
31873 el.fadeIn({callback: afterShow});
31879 var afterShow = function(){
31883 if(tm.autoDismiss && ce.autoHide !== false){
31884 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31889 var hide = function(noanim){
31890 clearTimeout(dismissProc);
31891 clearTimeout(hideProc);
31893 if(el.isVisible()){
31895 if(noanim !== true && tm.animate){
31896 el.fadeOut({callback: afterHide});
31903 var afterHide = function(){
31906 el.removeClass(removeCls);
31913 * @cfg {Number} minWidth
31914 * The minimum width of the quick tip (defaults to 40)
31918 * @cfg {Number} maxWidth
31919 * The maximum width of the quick tip (defaults to 300)
31923 * @cfg {Boolean} interceptTitles
31924 * True to automatically use the element's DOM title value if available (defaults to false)
31926 interceptTitles : false,
31928 * @cfg {Boolean} trackMouse
31929 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31931 trackMouse : false,
31933 * @cfg {Boolean} hideOnClick
31934 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
31936 hideOnClick : true,
31938 * @cfg {Number} showDelay
31939 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
31943 * @cfg {Number} hideDelay
31944 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
31948 * @cfg {Boolean} autoHide
31949 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
31950 * Used in conjunction with hideDelay.
31955 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
31956 * (defaults to true). Used in conjunction with autoDismissDelay.
31958 autoDismiss : true,
31961 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
31963 autoDismissDelay : 5000,
31965 * @cfg {Boolean} animate
31966 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
31971 * @cfg {String} title
31972 * Title text to display (defaults to ''). This can be any valid HTML markup.
31976 * @cfg {String} text
31977 * Body text to display (defaults to ''). This can be any valid HTML markup.
31981 * @cfg {String} cls
31982 * A CSS class to apply to the base quick tip element (defaults to '').
31986 * @cfg {Number} width
31987 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
31988 * minWidth or maxWidth.
31993 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
31994 * or display QuickTips in a page.
31997 tm = Roo.QuickTips;
31998 cfg = tm.tagConfig;
32000 if(!Roo.isReady){ // allow calling of init() before onReady
32001 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32004 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32005 el.fxDefaults = {stopFx: true};
32006 // maximum custom styling
32007 //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>');
32008 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>');
32009 tipTitle = el.child('h3');
32010 tipTitle.enableDisplayMode("block");
32011 tipBody = el.child('div.x-tip-bd');
32012 tipBodyText = el.child('div.x-tip-bd-inner');
32013 //bdLeft = el.child('div.x-tip-bd-left');
32014 //bdRight = el.child('div.x-tip-bd-right');
32015 close = el.child('div.x-tip-close');
32016 close.enableDisplayMode("block");
32017 close.on("click", hide);
32018 var d = Roo.get(document);
32019 d.on("mousedown", onDown);
32020 d.on("mouseover", onOver);
32021 d.on("mouseout", onOut);
32022 d.on("mousemove", onMove);
32023 esc = d.addKeyListener(27, hide);
32026 dd = el.initDD("default", null, {
32027 onDrag : function(){
32031 dd.setHandleElId(tipTitle.id);
32040 * Configures a new quick tip instance and assigns it to a target element. The following config options
32043 Property Type Description
32044 ---------- --------------------- ------------------------------------------------------------------------
32045 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32047 * @param {Object} config The config object
32049 register : function(config){
32050 var cs = config instanceof Array ? config : arguments;
32051 for(var i = 0, len = cs.length; i < len; i++) {
32053 var target = c.target;
32055 if(target instanceof Array){
32056 for(var j = 0, jlen = target.length; j < jlen; j++){
32057 tagEls[target[j]] = c;
32060 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32067 * Removes this quick tip from its element and destroys it.
32068 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32070 unregister : function(el){
32071 delete tagEls[Roo.id(el)];
32075 * Enable this quick tip.
32077 enable : function(){
32078 if(inited && disabled){
32080 if(locks.length < 1){
32087 * Disable this quick tip.
32089 disable : function(){
32091 clearTimeout(showProc);
32092 clearTimeout(hideProc);
32093 clearTimeout(dismissProc);
32101 * Returns true if the quick tip is enabled, else false.
32103 isEnabled : function(){
32110 attribute : "qtip",
32120 // backwards compat
32121 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32123 * Ext JS Library 1.1.1
32124 * Copyright(c) 2006-2007, Ext JS, LLC.
32126 * Originally Released Under LGPL - original licence link has changed is not relivant.
32129 * <script type="text/javascript">
32134 * @class Roo.tree.TreePanel
32135 * @extends Roo.data.Tree
32137 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32138 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32139 * @cfg {Boolean} enableDD true to enable drag and drop
32140 * @cfg {Boolean} enableDrag true to enable just drag
32141 * @cfg {Boolean} enableDrop true to enable just drop
32142 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32143 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32144 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32145 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32146 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32147 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32148 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32149 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32150 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32151 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32152 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32153 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32154 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32155 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32156 * @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>
32157 * @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>
32160 * @param {String/HTMLElement/Element} el The container element
32161 * @param {Object} config
32163 Roo.tree.TreePanel = function(el, config){
32165 var loader = false;
32167 root = config.root;
32168 delete config.root;
32170 if (config.loader) {
32171 loader = config.loader;
32172 delete config.loader;
32175 Roo.apply(this, config);
32176 Roo.tree.TreePanel.superclass.constructor.call(this);
32177 this.el = Roo.get(el);
32178 this.el.addClass('x-tree');
32179 //console.log(root);
32181 this.setRootNode( Roo.factory(root, Roo.tree));
32184 this.loader = Roo.factory(loader, Roo.tree);
32187 * Read-only. The id of the container element becomes this TreePanel's id.
32189 this.id = this.el.id;
32192 * @event beforeload
32193 * Fires before a node is loaded, return false to cancel
32194 * @param {Node} node The node being loaded
32196 "beforeload" : true,
32199 * Fires when a node is loaded
32200 * @param {Node} node The node that was loaded
32204 * @event textchange
32205 * Fires when the text for a node is changed
32206 * @param {Node} node The node
32207 * @param {String} text The new text
32208 * @param {String} oldText The old text
32210 "textchange" : true,
32212 * @event beforeexpand
32213 * Fires before a node is expanded, return false to cancel.
32214 * @param {Node} node The node
32215 * @param {Boolean} deep
32216 * @param {Boolean} anim
32218 "beforeexpand" : true,
32220 * @event beforecollapse
32221 * Fires before a node is collapsed, return false to cancel.
32222 * @param {Node} node The node
32223 * @param {Boolean} deep
32224 * @param {Boolean} anim
32226 "beforecollapse" : true,
32229 * Fires when a node is expanded
32230 * @param {Node} node The node
32234 * @event disabledchange
32235 * Fires when the disabled status of a node changes
32236 * @param {Node} node The node
32237 * @param {Boolean} disabled
32239 "disabledchange" : true,
32242 * Fires when a node is collapsed
32243 * @param {Node} node The node
32247 * @event beforeclick
32248 * Fires before click processing on a node. Return false to cancel the default action.
32249 * @param {Node} node The node
32250 * @param {Roo.EventObject} e The event object
32252 "beforeclick":true,
32254 * @event checkchange
32255 * Fires when a node with a checkbox's checked property changes
32256 * @param {Node} this This node
32257 * @param {Boolean} checked
32259 "checkchange":true,
32262 * Fires when a node is clicked
32263 * @param {Node} node The node
32264 * @param {Roo.EventObject} e The event object
32269 * Fires when a node is double clicked
32270 * @param {Node} node The node
32271 * @param {Roo.EventObject} e The event object
32275 * @event contextmenu
32276 * Fires when a node is right clicked
32277 * @param {Node} node The node
32278 * @param {Roo.EventObject} e The event object
32280 "contextmenu":true,
32282 * @event beforechildrenrendered
32283 * Fires right before the child nodes for a node are rendered
32284 * @param {Node} node The node
32286 "beforechildrenrendered":true,
32289 * Fires when a node starts being dragged
32290 * @param {Roo.tree.TreePanel} this
32291 * @param {Roo.tree.TreeNode} node
32292 * @param {event} e The raw browser event
32294 "startdrag" : true,
32297 * Fires when a drag operation is complete
32298 * @param {Roo.tree.TreePanel} this
32299 * @param {Roo.tree.TreeNode} node
32300 * @param {event} e The raw browser event
32305 * Fires when a dragged node is dropped on a valid DD target
32306 * @param {Roo.tree.TreePanel} this
32307 * @param {Roo.tree.TreeNode} node
32308 * @param {DD} dd The dd it was dropped on
32309 * @param {event} e The raw browser event
32313 * @event beforenodedrop
32314 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32315 * passed to handlers has the following properties:<br />
32316 * <ul style="padding:5px;padding-left:16px;">
32317 * <li>tree - The TreePanel</li>
32318 * <li>target - The node being targeted for the drop</li>
32319 * <li>data - The drag data from the drag source</li>
32320 * <li>point - The point of the drop - append, above or below</li>
32321 * <li>source - The drag source</li>
32322 * <li>rawEvent - Raw mouse event</li>
32323 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32324 * to be inserted by setting them on this object.</li>
32325 * <li>cancel - Set this to true to cancel the drop.</li>
32327 * @param {Object} dropEvent
32329 "beforenodedrop" : true,
32332 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32333 * passed to handlers has the following properties:<br />
32334 * <ul style="padding:5px;padding-left:16px;">
32335 * <li>tree - The TreePanel</li>
32336 * <li>target - The node being targeted for the drop</li>
32337 * <li>data - The drag data from the drag source</li>
32338 * <li>point - The point of the drop - append, above or below</li>
32339 * <li>source - The drag source</li>
32340 * <li>rawEvent - Raw mouse event</li>
32341 * <li>dropNode - Dropped node(s).</li>
32343 * @param {Object} dropEvent
32347 * @event nodedragover
32348 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32349 * passed to handlers has the following properties:<br />
32350 * <ul style="padding:5px;padding-left:16px;">
32351 * <li>tree - The TreePanel</li>
32352 * <li>target - The node being targeted for the drop</li>
32353 * <li>data - The drag data from the drag source</li>
32354 * <li>point - The point of the drop - append, above or below</li>
32355 * <li>source - The drag source</li>
32356 * <li>rawEvent - Raw mouse event</li>
32357 * <li>dropNode - Drop node(s) provided by the source.</li>
32358 * <li>cancel - Set this to true to signal drop not allowed.</li>
32360 * @param {Object} dragOverEvent
32362 "nodedragover" : true
32365 if(this.singleExpand){
32366 this.on("beforeexpand", this.restrictExpand, this);
32369 this.editor.tree = this;
32370 this.editor = Roo.factory(this.editor, Roo.tree);
32373 if (this.selModel) {
32374 this.selModel = Roo.factory(this.selModel, Roo.tree);
32378 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32379 rootVisible : true,
32380 animate: Roo.enableFx,
32383 hlDrop : Roo.enableFx,
32387 rendererTip: false,
32389 restrictExpand : function(node){
32390 var p = node.parentNode;
32392 if(p.expandedChild && p.expandedChild.parentNode == p){
32393 p.expandedChild.collapse();
32395 p.expandedChild = node;
32399 // private override
32400 setRootNode : function(node){
32401 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32402 if(!this.rootVisible){
32403 node.ui = new Roo.tree.RootTreeNodeUI(node);
32409 * Returns the container element for this TreePanel
32411 getEl : function(){
32416 * Returns the default TreeLoader for this TreePanel
32418 getLoader : function(){
32419 return this.loader;
32425 expandAll : function(){
32426 this.root.expand(true);
32430 * Collapse all nodes
32432 collapseAll : function(){
32433 this.root.collapse(true);
32437 * Returns the selection model used by this TreePanel
32439 getSelectionModel : function(){
32440 if(!this.selModel){
32441 this.selModel = new Roo.tree.DefaultSelectionModel();
32443 return this.selModel;
32447 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32448 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32449 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32452 getChecked : function(a, startNode){
32453 startNode = startNode || this.root;
32455 var f = function(){
32456 if(this.attributes.checked){
32457 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32460 startNode.cascade(f);
32465 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32466 * @param {String} path
32467 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32468 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32469 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32471 expandPath : function(path, attr, callback){
32472 attr = attr || "id";
32473 var keys = path.split(this.pathSeparator);
32474 var curNode = this.root;
32475 if(curNode.attributes[attr] != keys[1]){ // invalid root
32477 callback(false, null);
32482 var f = function(){
32483 if(++index == keys.length){
32485 callback(true, curNode);
32489 var c = curNode.findChild(attr, keys[index]);
32492 callback(false, curNode);
32497 c.expand(false, false, f);
32499 curNode.expand(false, false, f);
32503 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32504 * @param {String} path
32505 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32506 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32507 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32509 selectPath : function(path, attr, callback){
32510 attr = attr || "id";
32511 var keys = path.split(this.pathSeparator);
32512 var v = keys.pop();
32513 if(keys.length > 0){
32514 var f = function(success, node){
32515 if(success && node){
32516 var n = node.findChild(attr, v);
32522 }else if(callback){
32523 callback(false, n);
32527 callback(false, n);
32531 this.expandPath(keys.join(this.pathSeparator), attr, f);
32533 this.root.select();
32535 callback(true, this.root);
32540 getTreeEl : function(){
32545 * Trigger rendering of this TreePanel
32547 render : function(){
32548 if (this.innerCt) {
32549 return this; // stop it rendering more than once!!
32552 this.innerCt = this.el.createChild({tag:"ul",
32553 cls:"x-tree-root-ct " +
32554 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32556 if(this.containerScroll){
32557 Roo.dd.ScrollManager.register(this.el);
32559 if((this.enableDD || this.enableDrop) && !this.dropZone){
32561 * The dropZone used by this tree if drop is enabled
32562 * @type Roo.tree.TreeDropZone
32564 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32565 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32568 if((this.enableDD || this.enableDrag) && !this.dragZone){
32570 * The dragZone used by this tree if drag is enabled
32571 * @type Roo.tree.TreeDragZone
32573 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32574 ddGroup: this.ddGroup || "TreeDD",
32575 scroll: this.ddScroll
32578 this.getSelectionModel().init(this);
32580 Roo.log("ROOT not set in tree");
32583 this.root.render();
32584 if(!this.rootVisible){
32585 this.root.renderChildren();
32591 * Ext JS Library 1.1.1
32592 * Copyright(c) 2006-2007, Ext JS, LLC.
32594 * Originally Released Under LGPL - original licence link has changed is not relivant.
32597 * <script type="text/javascript">
32602 * @class Roo.tree.DefaultSelectionModel
32603 * @extends Roo.util.Observable
32604 * The default single selection for a TreePanel.
32605 * @param {Object} cfg Configuration
32607 Roo.tree.DefaultSelectionModel = function(cfg){
32608 this.selNode = null;
32614 * @event selectionchange
32615 * Fires when the selected node changes
32616 * @param {DefaultSelectionModel} this
32617 * @param {TreeNode} node the new selection
32619 "selectionchange" : true,
32622 * @event beforeselect
32623 * Fires before the selected node changes, return false to cancel the change
32624 * @param {DefaultSelectionModel} this
32625 * @param {TreeNode} node the new selection
32626 * @param {TreeNode} node the old selection
32628 "beforeselect" : true
32631 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32634 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32635 init : function(tree){
32637 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32638 tree.on("click", this.onNodeClick, this);
32641 onNodeClick : function(node, e){
32642 if (e.ctrlKey && this.selNode == node) {
32643 this.unselect(node);
32651 * @param {TreeNode} node The node to select
32652 * @return {TreeNode} The selected node
32654 select : function(node){
32655 var last = this.selNode;
32656 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32658 last.ui.onSelectedChange(false);
32660 this.selNode = node;
32661 node.ui.onSelectedChange(true);
32662 this.fireEvent("selectionchange", this, node, last);
32669 * @param {TreeNode} node The node to unselect
32671 unselect : function(node){
32672 if(this.selNode == node){
32673 this.clearSelections();
32678 * Clear all selections
32680 clearSelections : function(){
32681 var n = this.selNode;
32683 n.ui.onSelectedChange(false);
32684 this.selNode = null;
32685 this.fireEvent("selectionchange", this, null);
32691 * Get the selected node
32692 * @return {TreeNode} The selected node
32694 getSelectedNode : function(){
32695 return this.selNode;
32699 * Returns true if the node is selected
32700 * @param {TreeNode} node The node to check
32701 * @return {Boolean}
32703 isSelected : function(node){
32704 return this.selNode == node;
32708 * Selects the node above the selected node in the tree, intelligently walking the nodes
32709 * @return TreeNode The new selection
32711 selectPrevious : function(){
32712 var s = this.selNode || this.lastSelNode;
32716 var ps = s.previousSibling;
32718 if(!ps.isExpanded() || ps.childNodes.length < 1){
32719 return this.select(ps);
32721 var lc = ps.lastChild;
32722 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32725 return this.select(lc);
32727 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32728 return this.select(s.parentNode);
32734 * Selects the node above the selected node in the tree, intelligently walking the nodes
32735 * @return TreeNode The new selection
32737 selectNext : function(){
32738 var s = this.selNode || this.lastSelNode;
32742 if(s.firstChild && s.isExpanded()){
32743 return this.select(s.firstChild);
32744 }else if(s.nextSibling){
32745 return this.select(s.nextSibling);
32746 }else if(s.parentNode){
32748 s.parentNode.bubble(function(){
32749 if(this.nextSibling){
32750 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32759 onKeyDown : function(e){
32760 var s = this.selNode || this.lastSelNode;
32761 // undesirable, but required
32766 var k = e.getKey();
32774 this.selectPrevious();
32777 e.preventDefault();
32778 if(s.hasChildNodes()){
32779 if(!s.isExpanded()){
32781 }else if(s.firstChild){
32782 this.select(s.firstChild, e);
32787 e.preventDefault();
32788 if(s.hasChildNodes() && s.isExpanded()){
32790 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32791 this.select(s.parentNode, e);
32799 * @class Roo.tree.MultiSelectionModel
32800 * @extends Roo.util.Observable
32801 * Multi selection for a TreePanel.
32802 * @param {Object} cfg Configuration
32804 Roo.tree.MultiSelectionModel = function(){
32805 this.selNodes = [];
32809 * @event selectionchange
32810 * Fires when the selected nodes change
32811 * @param {MultiSelectionModel} this
32812 * @param {Array} nodes Array of the selected nodes
32814 "selectionchange" : true
32816 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32820 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32821 init : function(tree){
32823 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32824 tree.on("click", this.onNodeClick, this);
32827 onNodeClick : function(node, e){
32828 this.select(node, e, e.ctrlKey);
32833 * @param {TreeNode} node The node to select
32834 * @param {EventObject} e (optional) An event associated with the selection
32835 * @param {Boolean} keepExisting True to retain existing selections
32836 * @return {TreeNode} The selected node
32838 select : function(node, e, keepExisting){
32839 if(keepExisting !== true){
32840 this.clearSelections(true);
32842 if(this.isSelected(node)){
32843 this.lastSelNode = node;
32846 this.selNodes.push(node);
32847 this.selMap[node.id] = node;
32848 this.lastSelNode = node;
32849 node.ui.onSelectedChange(true);
32850 this.fireEvent("selectionchange", this, this.selNodes);
32856 * @param {TreeNode} node The node to unselect
32858 unselect : function(node){
32859 if(this.selMap[node.id]){
32860 node.ui.onSelectedChange(false);
32861 var sn = this.selNodes;
32864 index = sn.indexOf(node);
32866 for(var i = 0, len = sn.length; i < len; i++){
32874 this.selNodes.splice(index, 1);
32876 delete this.selMap[node.id];
32877 this.fireEvent("selectionchange", this, this.selNodes);
32882 * Clear all selections
32884 clearSelections : function(suppressEvent){
32885 var sn = this.selNodes;
32887 for(var i = 0, len = sn.length; i < len; i++){
32888 sn[i].ui.onSelectedChange(false);
32890 this.selNodes = [];
32892 if(suppressEvent !== true){
32893 this.fireEvent("selectionchange", this, this.selNodes);
32899 * Returns true if the node is selected
32900 * @param {TreeNode} node The node to check
32901 * @return {Boolean}
32903 isSelected : function(node){
32904 return this.selMap[node.id] ? true : false;
32908 * Returns an array of the selected nodes
32911 getSelectedNodes : function(){
32912 return this.selNodes;
32915 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32917 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32919 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32922 * Ext JS Library 1.1.1
32923 * Copyright(c) 2006-2007, Ext JS, LLC.
32925 * Originally Released Under LGPL - original licence link has changed is not relivant.
32928 * <script type="text/javascript">
32932 * @class Roo.tree.TreeNode
32933 * @extends Roo.data.Node
32934 * @cfg {String} text The text for this node
32935 * @cfg {Boolean} expanded true to start the node expanded
32936 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
32937 * @cfg {Boolean} allowDrop false if this node cannot be drop on
32938 * @cfg {Boolean} disabled true to start the node disabled
32939 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
32940 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
32941 * @cfg {String} cls A css class to be added to the node
32942 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
32943 * @cfg {String} href URL of the link used for the node (defaults to #)
32944 * @cfg {String} hrefTarget target frame for the link
32945 * @cfg {String} qtip An Ext QuickTip for the node
32946 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
32947 * @cfg {Boolean} singleClickExpand True for single click expand on this node
32948 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
32949 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
32950 * (defaults to undefined with no checkbox rendered)
32952 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32954 Roo.tree.TreeNode = function(attributes){
32955 attributes = attributes || {};
32956 if(typeof attributes == "string"){
32957 attributes = {text: attributes};
32959 this.childrenRendered = false;
32960 this.rendered = false;
32961 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
32962 this.expanded = attributes.expanded === true;
32963 this.isTarget = attributes.isTarget !== false;
32964 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
32965 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
32968 * Read-only. The text for this node. To change it use setText().
32971 this.text = attributes.text;
32973 * True if this node is disabled.
32976 this.disabled = attributes.disabled === true;
32980 * @event textchange
32981 * Fires when the text for this node is changed
32982 * @param {Node} this This node
32983 * @param {String} text The new text
32984 * @param {String} oldText The old text
32986 "textchange" : true,
32988 * @event beforeexpand
32989 * Fires before this node is expanded, return false to cancel.
32990 * @param {Node} this This node
32991 * @param {Boolean} deep
32992 * @param {Boolean} anim
32994 "beforeexpand" : true,
32996 * @event beforecollapse
32997 * Fires before this node is collapsed, return false to cancel.
32998 * @param {Node} this This node
32999 * @param {Boolean} deep
33000 * @param {Boolean} anim
33002 "beforecollapse" : true,
33005 * Fires when this node is expanded
33006 * @param {Node} this This node
33010 * @event disabledchange
33011 * Fires when the disabled status of this node changes
33012 * @param {Node} this This node
33013 * @param {Boolean} disabled
33015 "disabledchange" : true,
33018 * Fires when this node is collapsed
33019 * @param {Node} this This node
33023 * @event beforeclick
33024 * Fires before click processing. Return false to cancel the default action.
33025 * @param {Node} this This node
33026 * @param {Roo.EventObject} e The event object
33028 "beforeclick":true,
33030 * @event checkchange
33031 * Fires when a node with a checkbox's checked property changes
33032 * @param {Node} this This node
33033 * @param {Boolean} checked
33035 "checkchange":true,
33038 * Fires when this node is clicked
33039 * @param {Node} this This node
33040 * @param {Roo.EventObject} e The event object
33045 * Fires when this node is double clicked
33046 * @param {Node} this This node
33047 * @param {Roo.EventObject} e The event object
33051 * @event contextmenu
33052 * Fires when this node is right clicked
33053 * @param {Node} this This node
33054 * @param {Roo.EventObject} e The event object
33056 "contextmenu":true,
33058 * @event beforechildrenrendered
33059 * Fires right before the child nodes for this node are rendered
33060 * @param {Node} this This node
33062 "beforechildrenrendered":true
33065 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33068 * Read-only. The UI for this node
33071 this.ui = new uiClass(this);
33073 // finally support items[]
33074 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33079 Roo.each(this.attributes.items, function(c) {
33080 this.appendChild(Roo.factory(c,Roo.Tree));
33082 delete this.attributes.items;
33087 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33088 preventHScroll: true,
33090 * Returns true if this node is expanded
33091 * @return {Boolean}
33093 isExpanded : function(){
33094 return this.expanded;
33098 * Returns the UI object for this node
33099 * @return {TreeNodeUI}
33101 getUI : function(){
33105 // private override
33106 setFirstChild : function(node){
33107 var of = this.firstChild;
33108 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33109 if(this.childrenRendered && of && node != of){
33110 of.renderIndent(true, true);
33113 this.renderIndent(true, true);
33117 // private override
33118 setLastChild : function(node){
33119 var ol = this.lastChild;
33120 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33121 if(this.childrenRendered && ol && node != ol){
33122 ol.renderIndent(true, true);
33125 this.renderIndent(true, true);
33129 // these methods are overridden to provide lazy rendering support
33130 // private override
33131 appendChild : function()
33133 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33134 if(node && this.childrenRendered){
33137 this.ui.updateExpandIcon();
33141 // private override
33142 removeChild : function(node){
33143 this.ownerTree.getSelectionModel().unselect(node);
33144 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33145 // if it's been rendered remove dom node
33146 if(this.childrenRendered){
33149 if(this.childNodes.length < 1){
33150 this.collapse(false, false);
33152 this.ui.updateExpandIcon();
33154 if(!this.firstChild) {
33155 this.childrenRendered = false;
33160 // private override
33161 insertBefore : function(node, refNode){
33162 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33163 if(newNode && refNode && this.childrenRendered){
33166 this.ui.updateExpandIcon();
33171 * Sets the text for this node
33172 * @param {String} text
33174 setText : function(text){
33175 var oldText = this.text;
33177 this.attributes.text = text;
33178 if(this.rendered){ // event without subscribing
33179 this.ui.onTextChange(this, text, oldText);
33181 this.fireEvent("textchange", this, text, oldText);
33185 * Triggers selection of this node
33187 select : function(){
33188 this.getOwnerTree().getSelectionModel().select(this);
33192 * Triggers deselection of this node
33194 unselect : function(){
33195 this.getOwnerTree().getSelectionModel().unselect(this);
33199 * Returns true if this node is selected
33200 * @return {Boolean}
33202 isSelected : function(){
33203 return this.getOwnerTree().getSelectionModel().isSelected(this);
33207 * Expand this node.
33208 * @param {Boolean} deep (optional) True to expand all children as well
33209 * @param {Boolean} anim (optional) false to cancel the default animation
33210 * @param {Function} callback (optional) A callback to be called when
33211 * expanding this node completes (does not wait for deep expand to complete).
33212 * Called with 1 parameter, this node.
33214 expand : function(deep, anim, callback){
33215 if(!this.expanded){
33216 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33219 if(!this.childrenRendered){
33220 this.renderChildren();
33222 this.expanded = true;
33223 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33224 this.ui.animExpand(function(){
33225 this.fireEvent("expand", this);
33226 if(typeof callback == "function"){
33230 this.expandChildNodes(true);
33232 }.createDelegate(this));
33236 this.fireEvent("expand", this);
33237 if(typeof callback == "function"){
33242 if(typeof callback == "function"){
33247 this.expandChildNodes(true);
33251 isHiddenRoot : function(){
33252 return this.isRoot && !this.getOwnerTree().rootVisible;
33256 * Collapse this node.
33257 * @param {Boolean} deep (optional) True to collapse all children as well
33258 * @param {Boolean} anim (optional) false to cancel the default animation
33260 collapse : function(deep, anim){
33261 if(this.expanded && !this.isHiddenRoot()){
33262 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33265 this.expanded = false;
33266 if((this.getOwnerTree().animate && anim !== false) || anim){
33267 this.ui.animCollapse(function(){
33268 this.fireEvent("collapse", this);
33270 this.collapseChildNodes(true);
33272 }.createDelegate(this));
33275 this.ui.collapse();
33276 this.fireEvent("collapse", this);
33280 var cs = this.childNodes;
33281 for(var i = 0, len = cs.length; i < len; i++) {
33282 cs[i].collapse(true, false);
33288 delayedExpand : function(delay){
33289 if(!this.expandProcId){
33290 this.expandProcId = this.expand.defer(delay, this);
33295 cancelExpand : function(){
33296 if(this.expandProcId){
33297 clearTimeout(this.expandProcId);
33299 this.expandProcId = false;
33303 * Toggles expanded/collapsed state of the node
33305 toggle : function(){
33314 * Ensures all parent nodes are expanded
33316 ensureVisible : function(callback){
33317 var tree = this.getOwnerTree();
33318 tree.expandPath(this.parentNode.getPath(), false, function(){
33319 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33320 Roo.callback(callback);
33321 }.createDelegate(this));
33325 * Expand all child nodes
33326 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33328 expandChildNodes : function(deep){
33329 var cs = this.childNodes;
33330 for(var i = 0, len = cs.length; i < len; i++) {
33331 cs[i].expand(deep);
33336 * Collapse all child nodes
33337 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33339 collapseChildNodes : function(deep){
33340 var cs = this.childNodes;
33341 for(var i = 0, len = cs.length; i < len; i++) {
33342 cs[i].collapse(deep);
33347 * Disables this node
33349 disable : function(){
33350 this.disabled = true;
33352 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33353 this.ui.onDisableChange(this, true);
33355 this.fireEvent("disabledchange", this, true);
33359 * Enables this node
33361 enable : function(){
33362 this.disabled = false;
33363 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33364 this.ui.onDisableChange(this, false);
33366 this.fireEvent("disabledchange", this, false);
33370 renderChildren : function(suppressEvent){
33371 if(suppressEvent !== false){
33372 this.fireEvent("beforechildrenrendered", this);
33374 var cs = this.childNodes;
33375 for(var i = 0, len = cs.length; i < len; i++){
33376 cs[i].render(true);
33378 this.childrenRendered = true;
33382 sort : function(fn, scope){
33383 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33384 if(this.childrenRendered){
33385 var cs = this.childNodes;
33386 for(var i = 0, len = cs.length; i < len; i++){
33387 cs[i].render(true);
33393 render : function(bulkRender){
33394 this.ui.render(bulkRender);
33395 if(!this.rendered){
33396 this.rendered = true;
33398 this.expanded = false;
33399 this.expand(false, false);
33405 renderIndent : function(deep, refresh){
33407 this.ui.childIndent = null;
33409 this.ui.renderIndent();
33410 if(deep === true && this.childrenRendered){
33411 var cs = this.childNodes;
33412 for(var i = 0, len = cs.length; i < len; i++){
33413 cs[i].renderIndent(true, refresh);
33419 * Ext JS Library 1.1.1
33420 * Copyright(c) 2006-2007, Ext JS, LLC.
33422 * Originally Released Under LGPL - original licence link has changed is not relivant.
33425 * <script type="text/javascript">
33429 * @class Roo.tree.AsyncTreeNode
33430 * @extends Roo.tree.TreeNode
33431 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33433 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33435 Roo.tree.AsyncTreeNode = function(config){
33436 this.loaded = false;
33437 this.loading = false;
33438 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33440 * @event beforeload
33441 * Fires before this node is loaded, return false to cancel
33442 * @param {Node} this This node
33444 this.addEvents({'beforeload':true, 'load': true});
33447 * Fires when this node is loaded
33448 * @param {Node} this This node
33451 * The loader used by this node (defaults to using the tree's defined loader)
33456 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33457 expand : function(deep, anim, callback){
33458 if(this.loading){ // if an async load is already running, waiting til it's done
33460 var f = function(){
33461 if(!this.loading){ // done loading
33462 clearInterval(timer);
33463 this.expand(deep, anim, callback);
33465 }.createDelegate(this);
33466 timer = setInterval(f, 200);
33470 if(this.fireEvent("beforeload", this) === false){
33473 this.loading = true;
33474 this.ui.beforeLoad(this);
33475 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33477 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33481 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33485 * Returns true if this node is currently loading
33486 * @return {Boolean}
33488 isLoading : function(){
33489 return this.loading;
33492 loadComplete : function(deep, anim, callback){
33493 this.loading = false;
33494 this.loaded = true;
33495 this.ui.afterLoad(this);
33496 this.fireEvent("load", this);
33497 this.expand(deep, anim, callback);
33501 * Returns true if this node has been loaded
33502 * @return {Boolean}
33504 isLoaded : function(){
33505 return this.loaded;
33508 hasChildNodes : function(){
33509 if(!this.isLeaf() && !this.loaded){
33512 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33517 * Trigger a reload for this node
33518 * @param {Function} callback
33520 reload : function(callback){
33521 this.collapse(false, false);
33522 while(this.firstChild){
33523 this.removeChild(this.firstChild);
33525 this.childrenRendered = false;
33526 this.loaded = false;
33527 if(this.isHiddenRoot()){
33528 this.expanded = false;
33530 this.expand(false, false, callback);
33534 * Ext JS Library 1.1.1
33535 * Copyright(c) 2006-2007, Ext JS, LLC.
33537 * Originally Released Under LGPL - original licence link has changed is not relivant.
33540 * <script type="text/javascript">
33544 * @class Roo.tree.TreeNodeUI
33546 * @param {Object} node The node to render
33547 * The TreeNode UI implementation is separate from the
33548 * tree implementation. Unless you are customizing the tree UI,
33549 * you should never have to use this directly.
33551 Roo.tree.TreeNodeUI = function(node){
33553 this.rendered = false;
33554 this.animating = false;
33555 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33558 Roo.tree.TreeNodeUI.prototype = {
33559 removeChild : function(node){
33561 this.ctNode.removeChild(node.ui.getEl());
33565 beforeLoad : function(){
33566 this.addClass("x-tree-node-loading");
33569 afterLoad : function(){
33570 this.removeClass("x-tree-node-loading");
33573 onTextChange : function(node, text, oldText){
33575 this.textNode.innerHTML = text;
33579 onDisableChange : function(node, state){
33580 this.disabled = state;
33582 this.addClass("x-tree-node-disabled");
33584 this.removeClass("x-tree-node-disabled");
33588 onSelectedChange : function(state){
33591 this.addClass("x-tree-selected");
33594 this.removeClass("x-tree-selected");
33598 onMove : function(tree, node, oldParent, newParent, index, refNode){
33599 this.childIndent = null;
33601 var targetNode = newParent.ui.getContainer();
33602 if(!targetNode){//target not rendered
33603 this.holder = document.createElement("div");
33604 this.holder.appendChild(this.wrap);
33607 var insertBefore = refNode ? refNode.ui.getEl() : null;
33609 targetNode.insertBefore(this.wrap, insertBefore);
33611 targetNode.appendChild(this.wrap);
33613 this.node.renderIndent(true);
33617 addClass : function(cls){
33619 Roo.fly(this.elNode).addClass(cls);
33623 removeClass : function(cls){
33625 Roo.fly(this.elNode).removeClass(cls);
33629 remove : function(){
33631 this.holder = document.createElement("div");
33632 this.holder.appendChild(this.wrap);
33636 fireEvent : function(){
33637 return this.node.fireEvent.apply(this.node, arguments);
33640 initEvents : function(){
33641 this.node.on("move", this.onMove, this);
33642 var E = Roo.EventManager;
33643 var a = this.anchor;
33645 var el = Roo.fly(a, '_treeui');
33647 if(Roo.isOpera){ // opera render bug ignores the CSS
33648 el.setStyle("text-decoration", "none");
33651 el.on("click", this.onClick, this);
33652 el.on("dblclick", this.onDblClick, this);
33655 Roo.EventManager.on(this.checkbox,
33656 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33659 el.on("contextmenu", this.onContextMenu, this);
33661 var icon = Roo.fly(this.iconNode);
33662 icon.on("click", this.onClick, this);
33663 icon.on("dblclick", this.onDblClick, this);
33664 icon.on("contextmenu", this.onContextMenu, this);
33665 E.on(this.ecNode, "click", this.ecClick, this, true);
33667 if(this.node.disabled){
33668 this.addClass("x-tree-node-disabled");
33670 if(this.node.hidden){
33671 this.addClass("x-tree-node-disabled");
33673 var ot = this.node.getOwnerTree();
33674 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33675 if(dd && (!this.node.isRoot || ot.rootVisible)){
33676 Roo.dd.Registry.register(this.elNode, {
33678 handles: this.getDDHandles(),
33684 getDDHandles : function(){
33685 return [this.iconNode, this.textNode];
33690 this.wrap.style.display = "none";
33696 this.wrap.style.display = "";
33700 onContextMenu : function(e){
33701 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33702 e.preventDefault();
33704 this.fireEvent("contextmenu", this.node, e);
33708 onClick : function(e){
33713 if(this.fireEvent("beforeclick", this.node, e) !== false){
33714 if(!this.disabled && this.node.attributes.href){
33715 this.fireEvent("click", this.node, e);
33718 e.preventDefault();
33723 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33724 this.node.toggle();
33727 this.fireEvent("click", this.node, e);
33733 onDblClick : function(e){
33734 e.preventDefault();
33739 this.toggleCheck();
33741 if(!this.animating && this.node.hasChildNodes()){
33742 this.node.toggle();
33744 this.fireEvent("dblclick", this.node, e);
33747 onCheckChange : function(){
33748 var checked = this.checkbox.checked;
33749 this.node.attributes.checked = checked;
33750 this.fireEvent('checkchange', this.node, checked);
33753 ecClick : function(e){
33754 if(!this.animating && this.node.hasChildNodes()){
33755 this.node.toggle();
33759 startDrop : function(){
33760 this.dropping = true;
33763 // delayed drop so the click event doesn't get fired on a drop
33764 endDrop : function(){
33765 setTimeout(function(){
33766 this.dropping = false;
33767 }.createDelegate(this), 50);
33770 expand : function(){
33771 this.updateExpandIcon();
33772 this.ctNode.style.display = "";
33775 focus : function(){
33776 if(!this.node.preventHScroll){
33777 try{this.anchor.focus();
33779 }else if(!Roo.isIE){
33781 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33782 var l = noscroll.scrollLeft;
33783 this.anchor.focus();
33784 noscroll.scrollLeft = l;
33789 toggleCheck : function(value){
33790 var cb = this.checkbox;
33792 cb.checked = (value === undefined ? !cb.checked : value);
33798 this.anchor.blur();
33802 animExpand : function(callback){
33803 var ct = Roo.get(this.ctNode);
33805 if(!this.node.hasChildNodes()){
33806 this.updateExpandIcon();
33807 this.ctNode.style.display = "";
33808 Roo.callback(callback);
33811 this.animating = true;
33812 this.updateExpandIcon();
33815 callback : function(){
33816 this.animating = false;
33817 Roo.callback(callback);
33820 duration: this.node.ownerTree.duration || .25
33824 highlight : function(){
33825 var tree = this.node.getOwnerTree();
33826 Roo.fly(this.wrap).highlight(
33827 tree.hlColor || "C3DAF9",
33828 {endColor: tree.hlBaseColor}
33832 collapse : function(){
33833 this.updateExpandIcon();
33834 this.ctNode.style.display = "none";
33837 animCollapse : function(callback){
33838 var ct = Roo.get(this.ctNode);
33839 ct.enableDisplayMode('block');
33842 this.animating = true;
33843 this.updateExpandIcon();
33846 callback : function(){
33847 this.animating = false;
33848 Roo.callback(callback);
33851 duration: this.node.ownerTree.duration || .25
33855 getContainer : function(){
33856 return this.ctNode;
33859 getEl : function(){
33863 appendDDGhost : function(ghostNode){
33864 ghostNode.appendChild(this.elNode.cloneNode(true));
33867 getDDRepairXY : function(){
33868 return Roo.lib.Dom.getXY(this.iconNode);
33871 onRender : function(){
33875 render : function(bulkRender){
33876 var n = this.node, a = n.attributes;
33877 var targetNode = n.parentNode ?
33878 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33880 if(!this.rendered){
33881 this.rendered = true;
33883 this.renderElements(n, a, targetNode, bulkRender);
33886 if(this.textNode.setAttributeNS){
33887 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33889 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33892 this.textNode.setAttribute("ext:qtip", a.qtip);
33894 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33897 }else if(a.qtipCfg){
33898 a.qtipCfg.target = Roo.id(this.textNode);
33899 Roo.QuickTips.register(a.qtipCfg);
33902 if(!this.node.expanded){
33903 this.updateExpandIcon();
33906 if(bulkRender === true) {
33907 targetNode.appendChild(this.wrap);
33912 renderElements : function(n, a, targetNode, bulkRender)
33914 // add some indent caching, this helps performance when rendering a large tree
33915 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33916 var t = n.getOwnerTree();
33917 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33918 if (typeof(n.attributes.html) != 'undefined') {
33919 txt = n.attributes.html;
33921 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33922 var cb = typeof a.checked == 'boolean';
33923 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33924 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33925 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33926 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33927 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33928 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33929 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33930 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33931 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33932 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33935 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33936 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33937 n.nextSibling.ui.getEl(), buf.join(""));
33939 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33942 this.elNode = this.wrap.childNodes[0];
33943 this.ctNode = this.wrap.childNodes[1];
33944 var cs = this.elNode.childNodes;
33945 this.indentNode = cs[0];
33946 this.ecNode = cs[1];
33947 this.iconNode = cs[2];
33950 this.checkbox = cs[3];
33953 this.anchor = cs[index];
33954 this.textNode = cs[index].firstChild;
33957 getAnchor : function(){
33958 return this.anchor;
33961 getTextEl : function(){
33962 return this.textNode;
33965 getIconEl : function(){
33966 return this.iconNode;
33969 isChecked : function(){
33970 return this.checkbox ? this.checkbox.checked : false;
33973 updateExpandIcon : function(){
33975 var n = this.node, c1, c2;
33976 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
33977 var hasChild = n.hasChildNodes();
33981 c1 = "x-tree-node-collapsed";
33982 c2 = "x-tree-node-expanded";
33985 c1 = "x-tree-node-expanded";
33986 c2 = "x-tree-node-collapsed";
33989 this.removeClass("x-tree-node-leaf");
33990 this.wasLeaf = false;
33992 if(this.c1 != c1 || this.c2 != c2){
33993 Roo.fly(this.elNode).replaceClass(c1, c2);
33994 this.c1 = c1; this.c2 = c2;
33997 // this changes non-leafs into leafs if they have no children.
33998 // it's not very rational behaviour..
34000 if(!this.wasLeaf && this.node.leaf){
34001 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34004 this.wasLeaf = true;
34007 var ecc = "x-tree-ec-icon "+cls;
34008 if(this.ecc != ecc){
34009 this.ecNode.className = ecc;
34015 getChildIndent : function(){
34016 if(!this.childIndent){
34020 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34022 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34024 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34029 this.childIndent = buf.join("");
34031 return this.childIndent;
34034 renderIndent : function(){
34037 var p = this.node.parentNode;
34039 indent = p.ui.getChildIndent();
34041 if(this.indentMarkup != indent){ // don't rerender if not required
34042 this.indentNode.innerHTML = indent;
34043 this.indentMarkup = indent;
34045 this.updateExpandIcon();
34050 Roo.tree.RootTreeNodeUI = function(){
34051 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34053 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34054 render : function(){
34055 if(!this.rendered){
34056 var targetNode = this.node.ownerTree.innerCt.dom;
34057 this.node.expanded = true;
34058 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34059 this.wrap = this.ctNode = targetNode.firstChild;
34062 collapse : function(){
34064 expand : function(){
34068 * Ext JS Library 1.1.1
34069 * Copyright(c) 2006-2007, Ext JS, LLC.
34071 * Originally Released Under LGPL - original licence link has changed is not relivant.
34074 * <script type="text/javascript">
34077 * @class Roo.tree.TreeLoader
34078 * @extends Roo.util.Observable
34079 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34080 * nodes from a specified URL. The response must be a javascript Array definition
34081 * who's elements are node definition objects. eg:
34086 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34087 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34094 * The old style respose with just an array is still supported, but not recommended.
34097 * A server request is sent, and child nodes are loaded only when a node is expanded.
34098 * The loading node's id is passed to the server under the parameter name "node" to
34099 * enable the server to produce the correct child nodes.
34101 * To pass extra parameters, an event handler may be attached to the "beforeload"
34102 * event, and the parameters specified in the TreeLoader's baseParams property:
34104 myTreeLoader.on("beforeload", function(treeLoader, node) {
34105 this.baseParams.category = node.attributes.category;
34108 * This would pass an HTTP parameter called "category" to the server containing
34109 * the value of the Node's "category" attribute.
34111 * Creates a new Treeloader.
34112 * @param {Object} config A config object containing config properties.
34114 Roo.tree.TreeLoader = function(config){
34115 this.baseParams = {};
34116 this.requestMethod = "POST";
34117 Roo.apply(this, config);
34122 * @event beforeload
34123 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34124 * @param {Object} This TreeLoader object.
34125 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34126 * @param {Object} callback The callback function specified in the {@link #load} call.
34131 * Fires when the node has been successfuly loaded.
34132 * @param {Object} This TreeLoader object.
34133 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34134 * @param {Object} response The response object containing the data from the server.
34138 * @event loadexception
34139 * Fires if the network request failed.
34140 * @param {Object} This TreeLoader object.
34141 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34142 * @param {Object} response The response object containing the data from the server.
34144 loadexception : true,
34147 * Fires before a node is created, enabling you to return custom Node types
34148 * @param {Object} This TreeLoader object.
34149 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34154 Roo.tree.TreeLoader.superclass.constructor.call(this);
34157 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34159 * @cfg {String} dataUrl The URL from which to request a Json string which
34160 * specifies an array of node definition object representing the child nodes
34164 * @cfg {String} requestMethod either GET or POST
34165 * defaults to POST (due to BC)
34169 * @cfg {Object} baseParams (optional) An object containing properties which
34170 * specify HTTP parameters to be passed to each request for child nodes.
34173 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34174 * created by this loader. If the attributes sent by the server have an attribute in this object,
34175 * they take priority.
34178 * @cfg {Object} uiProviders (optional) An object containing properties which
34180 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34181 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34182 * <i>uiProvider</i> attribute of a returned child node is a string rather
34183 * than a reference to a TreeNodeUI implementation, this that string value
34184 * is used as a property name in the uiProviders object. You can define the provider named
34185 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34190 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34191 * child nodes before loading.
34193 clearOnLoad : true,
34196 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34197 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34198 * Grid query { data : [ .....] }
34203 * @cfg {String} queryParam (optional)
34204 * Name of the query as it will be passed on the querystring (defaults to 'node')
34205 * eg. the request will be ?node=[id]
34212 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34213 * This is called automatically when a node is expanded, but may be used to reload
34214 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34215 * @param {Roo.tree.TreeNode} node
34216 * @param {Function} callback
34218 load : function(node, callback){
34219 if(this.clearOnLoad){
34220 while(node.firstChild){
34221 node.removeChild(node.firstChild);
34224 if(node.attributes.children){ // preloaded json children
34225 var cs = node.attributes.children;
34226 for(var i = 0, len = cs.length; i < len; i++){
34227 node.appendChild(this.createNode(cs[i]));
34229 if(typeof callback == "function"){
34232 }else if(this.dataUrl){
34233 this.requestData(node, callback);
34237 getParams: function(node){
34238 var buf = [], bp = this.baseParams;
34239 for(var key in bp){
34240 if(typeof bp[key] != "function"){
34241 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34244 var n = this.queryParam === false ? 'node' : this.queryParam;
34245 buf.push(n + "=", encodeURIComponent(node.id));
34246 return buf.join("");
34249 requestData : function(node, callback){
34250 if(this.fireEvent("beforeload", this, node, callback) !== false){
34251 this.transId = Roo.Ajax.request({
34252 method:this.requestMethod,
34253 url: this.dataUrl||this.url,
34254 success: this.handleResponse,
34255 failure: this.handleFailure,
34257 argument: {callback: callback, node: node},
34258 params: this.getParams(node)
34261 // if the load is cancelled, make sure we notify
34262 // the node that we are done
34263 if(typeof callback == "function"){
34269 isLoading : function(){
34270 return this.transId ? true : false;
34273 abort : function(){
34274 if(this.isLoading()){
34275 Roo.Ajax.abort(this.transId);
34280 createNode : function(attr)
34282 // apply baseAttrs, nice idea Corey!
34283 if(this.baseAttrs){
34284 Roo.applyIf(attr, this.baseAttrs);
34286 if(this.applyLoader !== false){
34287 attr.loader = this;
34289 // uiProvider = depreciated..
34291 if(typeof(attr.uiProvider) == 'string'){
34292 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34293 /** eval:var:attr */ eval(attr.uiProvider);
34295 if(typeof(this.uiProviders['default']) != 'undefined') {
34296 attr.uiProvider = this.uiProviders['default'];
34299 this.fireEvent('create', this, attr);
34301 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34303 new Roo.tree.TreeNode(attr) :
34304 new Roo.tree.AsyncTreeNode(attr));
34307 processResponse : function(response, node, callback)
34309 var json = response.responseText;
34312 var o = Roo.decode(json);
34314 if (this.root === false && typeof(o.success) != undefined) {
34315 this.root = 'data'; // the default behaviour for list like data..
34318 if (this.root !== false && !o.success) {
34319 // it's a failure condition.
34320 var a = response.argument;
34321 this.fireEvent("loadexception", this, a.node, response);
34322 Roo.log("Load failed - should have a handler really");
34328 if (this.root !== false) {
34332 for(var i = 0, len = o.length; i < len; i++){
34333 var n = this.createNode(o[i]);
34335 node.appendChild(n);
34338 if(typeof callback == "function"){
34339 callback(this, node);
34342 this.handleFailure(response);
34346 handleResponse : function(response){
34347 this.transId = false;
34348 var a = response.argument;
34349 this.processResponse(response, a.node, a.callback);
34350 this.fireEvent("load", this, a.node, response);
34353 handleFailure : function(response)
34355 // should handle failure better..
34356 this.transId = false;
34357 var a = response.argument;
34358 this.fireEvent("loadexception", this, a.node, response);
34359 if(typeof a.callback == "function"){
34360 a.callback(this, a.node);
34365 * Ext JS Library 1.1.1
34366 * Copyright(c) 2006-2007, Ext JS, LLC.
34368 * Originally Released Under LGPL - original licence link has changed is not relivant.
34371 * <script type="text/javascript">
34375 * @class Roo.tree.TreeFilter
34376 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34377 * @param {TreePanel} tree
34378 * @param {Object} config (optional)
34380 Roo.tree.TreeFilter = function(tree, config){
34382 this.filtered = {};
34383 Roo.apply(this, config);
34386 Roo.tree.TreeFilter.prototype = {
34393 * Filter the data by a specific attribute.
34394 * @param {String/RegExp} value Either string that the attribute value
34395 * should start with or a RegExp to test against the attribute
34396 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34397 * @param {TreeNode} startNode (optional) The node to start the filter at.
34399 filter : function(value, attr, startNode){
34400 attr = attr || "text";
34402 if(typeof value == "string"){
34403 var vlen = value.length;
34404 // auto clear empty filter
34405 if(vlen == 0 && this.clearBlank){
34409 value = value.toLowerCase();
34411 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34413 }else if(value.exec){ // regex?
34415 return value.test(n.attributes[attr]);
34418 throw 'Illegal filter type, must be string or regex';
34420 this.filterBy(f, null, startNode);
34424 * Filter by a function. The passed function will be called with each
34425 * node in the tree (or from the startNode). If the function returns true, the node is kept
34426 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34427 * @param {Function} fn The filter function
34428 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34430 filterBy : function(fn, scope, startNode){
34431 startNode = startNode || this.tree.root;
34432 if(this.autoClear){
34435 var af = this.filtered, rv = this.reverse;
34436 var f = function(n){
34437 if(n == startNode){
34443 var m = fn.call(scope || n, n);
34451 startNode.cascade(f);
34454 if(typeof id != "function"){
34456 if(n && n.parentNode){
34457 n.parentNode.removeChild(n);
34465 * Clears the current filter. Note: with the "remove" option
34466 * set a filter cannot be cleared.
34468 clear : function(){
34470 var af = this.filtered;
34472 if(typeof id != "function"){
34479 this.filtered = {};
34484 * Ext JS Library 1.1.1
34485 * Copyright(c) 2006-2007, Ext JS, LLC.
34487 * Originally Released Under LGPL - original licence link has changed is not relivant.
34490 * <script type="text/javascript">
34495 * @class Roo.tree.TreeSorter
34496 * Provides sorting of nodes in a TreePanel
34498 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34499 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34500 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34501 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34502 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34503 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34505 * @param {TreePanel} tree
34506 * @param {Object} config
34508 Roo.tree.TreeSorter = function(tree, config){
34509 Roo.apply(this, config);
34510 tree.on("beforechildrenrendered", this.doSort, this);
34511 tree.on("append", this.updateSort, this);
34512 tree.on("insert", this.updateSort, this);
34514 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34515 var p = this.property || "text";
34516 var sortType = this.sortType;
34517 var fs = this.folderSort;
34518 var cs = this.caseSensitive === true;
34519 var leafAttr = this.leafAttr || 'leaf';
34521 this.sortFn = function(n1, n2){
34523 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34526 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34530 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34531 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34533 return dsc ? +1 : -1;
34535 return dsc ? -1 : +1;
34542 Roo.tree.TreeSorter.prototype = {
34543 doSort : function(node){
34544 node.sort(this.sortFn);
34547 compareNodes : function(n1, n2){
34548 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34551 updateSort : function(tree, node){
34552 if(node.childrenRendered){
34553 this.doSort.defer(1, this, [node]);
34558 * Ext JS Library 1.1.1
34559 * Copyright(c) 2006-2007, Ext JS, LLC.
34561 * Originally Released Under LGPL - original licence link has changed is not relivant.
34564 * <script type="text/javascript">
34567 if(Roo.dd.DropZone){
34569 Roo.tree.TreeDropZone = function(tree, config){
34570 this.allowParentInsert = false;
34571 this.allowContainerDrop = false;
34572 this.appendOnly = false;
34573 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34575 this.lastInsertClass = "x-tree-no-status";
34576 this.dragOverData = {};
34579 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34580 ddGroup : "TreeDD",
34583 expandDelay : 1000,
34585 expandNode : function(node){
34586 if(node.hasChildNodes() && !node.isExpanded()){
34587 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34591 queueExpand : function(node){
34592 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34595 cancelExpand : function(){
34596 if(this.expandProcId){
34597 clearTimeout(this.expandProcId);
34598 this.expandProcId = false;
34602 isValidDropPoint : function(n, pt, dd, e, data){
34603 if(!n || !data){ return false; }
34604 var targetNode = n.node;
34605 var dropNode = data.node;
34606 // default drop rules
34607 if(!(targetNode && targetNode.isTarget && pt)){
34610 if(pt == "append" && targetNode.allowChildren === false){
34613 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34616 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34619 // reuse the object
34620 var overEvent = this.dragOverData;
34621 overEvent.tree = this.tree;
34622 overEvent.target = targetNode;
34623 overEvent.data = data;
34624 overEvent.point = pt;
34625 overEvent.source = dd;
34626 overEvent.rawEvent = e;
34627 overEvent.dropNode = dropNode;
34628 overEvent.cancel = false;
34629 var result = this.tree.fireEvent("nodedragover", overEvent);
34630 return overEvent.cancel === false && result !== false;
34633 getDropPoint : function(e, n, dd)
34637 return tn.allowChildren !== false ? "append" : false; // always append for root
34639 var dragEl = n.ddel;
34640 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34641 var y = Roo.lib.Event.getPageY(e);
34642 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34644 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34645 var noAppend = tn.allowChildren === false;
34646 if(this.appendOnly || tn.parentNode.allowChildren === false){
34647 return noAppend ? false : "append";
34649 var noBelow = false;
34650 if(!this.allowParentInsert){
34651 noBelow = tn.hasChildNodes() && tn.isExpanded();
34653 var q = (b - t) / (noAppend ? 2 : 3);
34654 if(y >= t && y < (t + q)){
34656 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34663 onNodeEnter : function(n, dd, e, data)
34665 this.cancelExpand();
34668 onNodeOver : function(n, dd, e, data)
34671 var pt = this.getDropPoint(e, n, dd);
34674 // auto node expand check
34675 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34676 this.queueExpand(node);
34677 }else if(pt != "append"){
34678 this.cancelExpand();
34681 // set the insert point style on the target node
34682 var returnCls = this.dropNotAllowed;
34683 if(this.isValidDropPoint(n, pt, dd, e, data)){
34688 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34689 cls = "x-tree-drag-insert-above";
34690 }else if(pt == "below"){
34691 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34692 cls = "x-tree-drag-insert-below";
34694 returnCls = "x-tree-drop-ok-append";
34695 cls = "x-tree-drag-append";
34697 if(this.lastInsertClass != cls){
34698 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34699 this.lastInsertClass = cls;
34706 onNodeOut : function(n, dd, e, data){
34708 this.cancelExpand();
34709 this.removeDropIndicators(n);
34712 onNodeDrop : function(n, dd, e, data){
34713 var point = this.getDropPoint(e, n, dd);
34714 var targetNode = n.node;
34715 targetNode.ui.startDrop();
34716 if(!this.isValidDropPoint(n, point, dd, e, data)){
34717 targetNode.ui.endDrop();
34720 // first try to find the drop node
34721 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34724 target: targetNode,
34729 dropNode: dropNode,
34732 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34733 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34734 targetNode.ui.endDrop();
34737 // allow target changing
34738 targetNode = dropEvent.target;
34739 if(point == "append" && !targetNode.isExpanded()){
34740 targetNode.expand(false, null, function(){
34741 this.completeDrop(dropEvent);
34742 }.createDelegate(this));
34744 this.completeDrop(dropEvent);
34749 completeDrop : function(de){
34750 var ns = de.dropNode, p = de.point, t = de.target;
34751 if(!(ns instanceof Array)){
34755 for(var i = 0, len = ns.length; i < len; i++){
34758 t.parentNode.insertBefore(n, t);
34759 }else if(p == "below"){
34760 t.parentNode.insertBefore(n, t.nextSibling);
34766 if(this.tree.hlDrop){
34770 this.tree.fireEvent("nodedrop", de);
34773 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34774 if(this.tree.hlDrop){
34775 dropNode.ui.focus();
34776 dropNode.ui.highlight();
34778 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34781 getTree : function(){
34785 removeDropIndicators : function(n){
34788 Roo.fly(el).removeClass([
34789 "x-tree-drag-insert-above",
34790 "x-tree-drag-insert-below",
34791 "x-tree-drag-append"]);
34792 this.lastInsertClass = "_noclass";
34796 beforeDragDrop : function(target, e, id){
34797 this.cancelExpand();
34801 afterRepair : function(data){
34802 if(data && Roo.enableFx){
34803 data.node.ui.highlight();
34813 * Ext JS Library 1.1.1
34814 * Copyright(c) 2006-2007, Ext JS, LLC.
34816 * Originally Released Under LGPL - original licence link has changed is not relivant.
34819 * <script type="text/javascript">
34823 if(Roo.dd.DragZone){
34824 Roo.tree.TreeDragZone = function(tree, config){
34825 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34829 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34830 ddGroup : "TreeDD",
34832 onBeforeDrag : function(data, e){
34834 return n && n.draggable && !n.disabled;
34838 onInitDrag : function(e){
34839 var data = this.dragData;
34840 this.tree.getSelectionModel().select(data.node);
34841 this.proxy.update("");
34842 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34843 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34846 getRepairXY : function(e, data){
34847 return data.node.ui.getDDRepairXY();
34850 onEndDrag : function(data, e){
34851 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34856 onValidDrop : function(dd, e, id){
34857 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34861 beforeInvalidDrop : function(e, id){
34862 // this scrolls the original position back into view
34863 var sm = this.tree.getSelectionModel();
34864 sm.clearSelections();
34865 sm.select(this.dragData.node);
34870 * Ext JS Library 1.1.1
34871 * Copyright(c) 2006-2007, Ext JS, LLC.
34873 * Originally Released Under LGPL - original licence link has changed is not relivant.
34876 * <script type="text/javascript">
34879 * @class Roo.tree.TreeEditor
34880 * @extends Roo.Editor
34881 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34882 * as the editor field.
34884 * @param {Object} config (used to be the tree panel.)
34885 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34887 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34888 * @cfg {Roo.form.TextField|Object} field The field configuration
34892 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34895 if (oldconfig) { // old style..
34896 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34899 tree = config.tree;
34900 config.field = config.field || {};
34901 config.field.xtype = 'TextField';
34902 field = Roo.factory(config.field, Roo.form);
34904 config = config || {};
34909 * @event beforenodeedit
34910 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34911 * false from the handler of this event.
34912 * @param {Editor} this
34913 * @param {Roo.tree.Node} node
34915 "beforenodeedit" : true
34919 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34923 tree.on('beforeclick', this.beforeNodeClick, this);
34924 tree.getTreeEl().on('mousedown', this.hide, this);
34925 this.on('complete', this.updateNode, this);
34926 this.on('beforestartedit', this.fitToTree, this);
34927 this.on('startedit', this.bindScroll, this, {delay:10});
34928 this.on('specialkey', this.onSpecialKey, this);
34931 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34933 * @cfg {String} alignment
34934 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
34940 * @cfg {Boolean} hideEl
34941 * True to hide the bound element while the editor is displayed (defaults to false)
34945 * @cfg {String} cls
34946 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
34948 cls: "x-small-editor x-tree-editor",
34950 * @cfg {Boolean} shim
34951 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
34957 * @cfg {Number} maxWidth
34958 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
34959 * the containing tree element's size, it will be automatically limited for you to the container width, taking
34960 * scroll and client offsets into account prior to each edit.
34967 fitToTree : function(ed, el){
34968 var td = this.tree.getTreeEl().dom, nd = el.dom;
34969 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
34970 td.scrollLeft = nd.offsetLeft;
34974 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
34975 this.setSize(w, '');
34977 return this.fireEvent('beforenodeedit', this, this.editNode);
34982 triggerEdit : function(node){
34983 this.completeEdit();
34984 this.editNode = node;
34985 this.startEdit(node.ui.textNode, node.text);
34989 bindScroll : function(){
34990 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
34994 beforeNodeClick : function(node, e){
34995 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
34996 this.lastClick = new Date();
34997 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
34999 this.triggerEdit(node);
35006 updateNode : function(ed, value){
35007 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35008 this.editNode.setText(value);
35012 onHide : function(){
35013 Roo.tree.TreeEditor.superclass.onHide.call(this);
35015 this.editNode.ui.focus();
35020 onSpecialKey : function(field, e){
35021 var k = e.getKey();
35025 }else if(k == e.ENTER && !e.hasModifier()){
35027 this.completeEdit();
35030 });//<Script type="text/javascript">
35033 * Ext JS Library 1.1.1
35034 * Copyright(c) 2006-2007, Ext JS, LLC.
35036 * Originally Released Under LGPL - original licence link has changed is not relivant.
35039 * <script type="text/javascript">
35043 * Not documented??? - probably should be...
35046 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35047 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35049 renderElements : function(n, a, targetNode, bulkRender){
35050 //consel.log("renderElements?");
35051 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35053 var t = n.getOwnerTree();
35054 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35056 var cols = t.columns;
35057 var bw = t.borderWidth;
35059 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35060 var cb = typeof a.checked == "boolean";
35061 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35062 var colcls = 'x-t-' + tid + '-c0';
35064 '<li class="x-tree-node">',
35067 '<div class="x-tree-node-el ', a.cls,'">',
35069 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35072 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35073 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35074 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35075 (a.icon ? ' x-tree-node-inline-icon' : ''),
35076 (a.iconCls ? ' '+a.iconCls : ''),
35077 '" unselectable="on" />',
35078 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35079 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35081 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35082 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35083 '<span unselectable="on" qtip="' + tx + '">',
35087 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35088 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35090 for(var i = 1, len = cols.length; i < len; i++){
35092 colcls = 'x-t-' + tid + '-c' +i;
35093 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35094 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35095 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35101 '<div class="x-clear"></div></div>',
35102 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35105 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35106 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35107 n.nextSibling.ui.getEl(), buf.join(""));
35109 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35111 var el = this.wrap.firstChild;
35113 this.elNode = el.firstChild;
35114 this.ranchor = el.childNodes[1];
35115 this.ctNode = this.wrap.childNodes[1];
35116 var cs = el.firstChild.childNodes;
35117 this.indentNode = cs[0];
35118 this.ecNode = cs[1];
35119 this.iconNode = cs[2];
35122 this.checkbox = cs[3];
35125 this.anchor = cs[index];
35127 this.textNode = cs[index].firstChild;
35129 //el.on("click", this.onClick, this);
35130 //el.on("dblclick", this.onDblClick, this);
35133 // console.log(this);
35135 initEvents : function(){
35136 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35139 var a = this.ranchor;
35141 var el = Roo.get(a);
35143 if(Roo.isOpera){ // opera render bug ignores the CSS
35144 el.setStyle("text-decoration", "none");
35147 el.on("click", this.onClick, this);
35148 el.on("dblclick", this.onDblClick, this);
35149 el.on("contextmenu", this.onContextMenu, this);
35153 /*onSelectedChange : function(state){
35156 this.addClass("x-tree-selected");
35159 this.removeClass("x-tree-selected");
35162 addClass : function(cls){
35164 Roo.fly(this.elRow).addClass(cls);
35170 removeClass : function(cls){
35172 Roo.fly(this.elRow).removeClass(cls);
35178 });//<Script type="text/javascript">
35182 * Ext JS Library 1.1.1
35183 * Copyright(c) 2006-2007, Ext JS, LLC.
35185 * Originally Released Under LGPL - original licence link has changed is not relivant.
35188 * <script type="text/javascript">
35193 * @class Roo.tree.ColumnTree
35194 * @extends Roo.data.TreePanel
35195 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35196 * @cfg {int} borderWidth compined right/left border allowance
35198 * @param {String/HTMLElement/Element} el The container element
35199 * @param {Object} config
35201 Roo.tree.ColumnTree = function(el, config)
35203 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35207 * Fire this event on a container when it resizes
35208 * @param {int} w Width
35209 * @param {int} h Height
35213 this.on('resize', this.onResize, this);
35216 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35220 borderWidth: Roo.isBorderBox ? 0 : 2,
35223 render : function(){
35224 // add the header.....
35226 Roo.tree.ColumnTree.superclass.render.apply(this);
35228 this.el.addClass('x-column-tree');
35230 this.headers = this.el.createChild(
35231 {cls:'x-tree-headers'},this.innerCt.dom);
35233 var cols = this.columns, c;
35234 var totalWidth = 0;
35236 var len = cols.length;
35237 for(var i = 0; i < len; i++){
35239 totalWidth += c.width;
35240 this.headEls.push(this.headers.createChild({
35241 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35243 cls:'x-tree-hd-text',
35246 style:'width:'+(c.width-this.borderWidth)+'px;'
35249 this.headers.createChild({cls:'x-clear'});
35250 // prevent floats from wrapping when clipped
35251 this.headers.setWidth(totalWidth);
35252 //this.innerCt.setWidth(totalWidth);
35253 this.innerCt.setStyle({ overflow: 'auto' });
35254 this.onResize(this.width, this.height);
35258 onResize : function(w,h)
35263 this.innerCt.setWidth(this.width);
35264 this.innerCt.setHeight(this.height-20);
35267 var cols = this.columns, c;
35268 var totalWidth = 0;
35270 var len = cols.length;
35271 for(var i = 0; i < len; i++){
35273 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35274 // it's the expander..
35275 expEl = this.headEls[i];
35278 totalWidth += c.width;
35282 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35284 this.headers.setWidth(w-20);
35293 * Ext JS Library 1.1.1
35294 * Copyright(c) 2006-2007, Ext JS, LLC.
35296 * Originally Released Under LGPL - original licence link has changed is not relivant.
35299 * <script type="text/javascript">
35303 * @class Roo.menu.Menu
35304 * @extends Roo.util.Observable
35305 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35306 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35308 * Creates a new Menu
35309 * @param {Object} config Configuration options
35311 Roo.menu.Menu = function(config){
35312 Roo.apply(this, config);
35313 this.id = this.id || Roo.id();
35316 * @event beforeshow
35317 * Fires before this menu is displayed
35318 * @param {Roo.menu.Menu} this
35322 * @event beforehide
35323 * Fires before this menu is hidden
35324 * @param {Roo.menu.Menu} this
35329 * Fires after this menu is displayed
35330 * @param {Roo.menu.Menu} this
35335 * Fires after this menu is hidden
35336 * @param {Roo.menu.Menu} this
35341 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35342 * @param {Roo.menu.Menu} this
35343 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35344 * @param {Roo.EventObject} e
35349 * Fires when the mouse is hovering over this menu
35350 * @param {Roo.menu.Menu} this
35351 * @param {Roo.EventObject} e
35352 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35357 * Fires when the mouse exits this menu
35358 * @param {Roo.menu.Menu} this
35359 * @param {Roo.EventObject} e
35360 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35365 * Fires when a menu item contained in this menu is clicked
35366 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35367 * @param {Roo.EventObject} e
35371 if (this.registerMenu) {
35372 Roo.menu.MenuMgr.register(this);
35375 var mis = this.items;
35376 this.items = new Roo.util.MixedCollection();
35378 this.add.apply(this, mis);
35382 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35384 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35388 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35389 * for bottom-right shadow (defaults to "sides")
35393 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35394 * this menu (defaults to "tl-tr?")
35396 subMenuAlign : "tl-tr?",
35398 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35399 * relative to its element of origin (defaults to "tl-bl?")
35401 defaultAlign : "tl-bl?",
35403 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35405 allowOtherMenus : false,
35407 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35409 registerMenu : true,
35414 render : function(){
35418 var el = this.el = new Roo.Layer({
35420 shadow:this.shadow,
35422 parentEl: this.parentEl || document.body,
35426 this.keyNav = new Roo.menu.MenuNav(this);
35429 el.addClass("x-menu-plain");
35432 el.addClass(this.cls);
35434 // generic focus element
35435 this.focusEl = el.createChild({
35436 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35438 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35439 ul.on("click", this.onClick, this);
35440 ul.on("mouseover", this.onMouseOver, this);
35441 ul.on("mouseout", this.onMouseOut, this);
35442 this.items.each(function(item){
35447 var li = document.createElement("li");
35448 li.className = "x-menu-list-item";
35449 ul.dom.appendChild(li);
35450 item.render(li, this);
35457 autoWidth : function(){
35458 var el = this.el, ul = this.ul;
35462 var w = this.width;
35465 }else if(Roo.isIE){
35466 el.setWidth(this.minWidth);
35467 var t = el.dom.offsetWidth; // force recalc
35468 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35473 delayAutoWidth : function(){
35476 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35478 this.awTask.delay(20);
35483 findTargetItem : function(e){
35484 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35485 if(t && t.menuItemId){
35486 return this.items.get(t.menuItemId);
35491 onClick : function(e){
35493 if(t = this.findTargetItem(e)){
35495 this.fireEvent("click", this, t, e);
35500 setActiveItem : function(item, autoExpand){
35501 if(item != this.activeItem){
35502 if(this.activeItem){
35503 this.activeItem.deactivate();
35505 this.activeItem = item;
35506 item.activate(autoExpand);
35507 }else if(autoExpand){
35513 tryActivate : function(start, step){
35514 var items = this.items;
35515 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35516 var item = items.get(i);
35517 if(!item.disabled && item.canActivate){
35518 this.setActiveItem(item, false);
35526 onMouseOver : function(e){
35528 if(t = this.findTargetItem(e)){
35529 if(t.canActivate && !t.disabled){
35530 this.setActiveItem(t, true);
35533 this.fireEvent("mouseover", this, e, t);
35537 onMouseOut : function(e){
35539 if(t = this.findTargetItem(e)){
35540 if(t == this.activeItem && t.shouldDeactivate(e)){
35541 this.activeItem.deactivate();
35542 delete this.activeItem;
35545 this.fireEvent("mouseout", this, e, t);
35549 * Read-only. Returns true if the menu is currently displayed, else false.
35552 isVisible : function(){
35553 return this.el && !this.hidden;
35557 * Displays this menu relative to another element
35558 * @param {String/HTMLElement/Roo.Element} element The element to align to
35559 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35560 * the element (defaults to this.defaultAlign)
35561 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35563 show : function(el, pos, parentMenu){
35564 this.parentMenu = parentMenu;
35568 this.fireEvent("beforeshow", this);
35569 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35573 * Displays this menu at a specific xy position
35574 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35575 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35577 showAt : function(xy, parentMenu, /* private: */_e){
35578 this.parentMenu = parentMenu;
35583 this.fireEvent("beforeshow", this);
35584 xy = this.el.adjustForConstraints(xy);
35588 this.hidden = false;
35590 this.fireEvent("show", this);
35593 focus : function(){
35595 this.doFocus.defer(50, this);
35599 doFocus : function(){
35601 this.focusEl.focus();
35606 * Hides this menu and optionally all parent menus
35607 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35609 hide : function(deep){
35610 if(this.el && this.isVisible()){
35611 this.fireEvent("beforehide", this);
35612 if(this.activeItem){
35613 this.activeItem.deactivate();
35614 this.activeItem = null;
35617 this.hidden = true;
35618 this.fireEvent("hide", this);
35620 if(deep === true && this.parentMenu){
35621 this.parentMenu.hide(true);
35626 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35627 * Any of the following are valid:
35629 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35630 * <li>An HTMLElement object which will be converted to a menu item</li>
35631 * <li>A menu item config object that will be created as a new menu item</li>
35632 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35633 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35638 var menu = new Roo.menu.Menu();
35640 // Create a menu item to add by reference
35641 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35643 // Add a bunch of items at once using different methods.
35644 // Only the last item added will be returned.
35645 var item = menu.add(
35646 menuItem, // add existing item by ref
35647 'Dynamic Item', // new TextItem
35648 '-', // new separator
35649 { text: 'Config Item' } // new item by config
35652 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35653 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35656 var a = arguments, l = a.length, item;
35657 for(var i = 0; i < l; i++){
35659 if ((typeof(el) == "object") && el.xtype && el.xns) {
35660 el = Roo.factory(el, Roo.menu);
35663 if(el.render){ // some kind of Item
35664 item = this.addItem(el);
35665 }else if(typeof el == "string"){ // string
35666 if(el == "separator" || el == "-"){
35667 item = this.addSeparator();
35669 item = this.addText(el);
35671 }else if(el.tagName || el.el){ // element
35672 item = this.addElement(el);
35673 }else if(typeof el == "object"){ // must be menu item config?
35674 item = this.addMenuItem(el);
35681 * Returns this menu's underlying {@link Roo.Element} object
35682 * @return {Roo.Element} The element
35684 getEl : function(){
35692 * Adds a separator bar to the menu
35693 * @return {Roo.menu.Item} The menu item that was added
35695 addSeparator : function(){
35696 return this.addItem(new Roo.menu.Separator());
35700 * Adds an {@link Roo.Element} object to the menu
35701 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35702 * @return {Roo.menu.Item} The menu item that was added
35704 addElement : function(el){
35705 return this.addItem(new Roo.menu.BaseItem(el));
35709 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35710 * @param {Roo.menu.Item} item The menu item to add
35711 * @return {Roo.menu.Item} The menu item that was added
35713 addItem : function(item){
35714 this.items.add(item);
35716 var li = document.createElement("li");
35717 li.className = "x-menu-list-item";
35718 this.ul.dom.appendChild(li);
35719 item.render(li, this);
35720 this.delayAutoWidth();
35726 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35727 * @param {Object} config A MenuItem config object
35728 * @return {Roo.menu.Item} The menu item that was added
35730 addMenuItem : function(config){
35731 if(!(config instanceof Roo.menu.Item)){
35732 if(typeof config.checked == "boolean"){ // must be check menu item config?
35733 config = new Roo.menu.CheckItem(config);
35735 config = new Roo.menu.Item(config);
35738 return this.addItem(config);
35742 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35743 * @param {String} text The text to display in the menu item
35744 * @return {Roo.menu.Item} The menu item that was added
35746 addText : function(text){
35747 return this.addItem(new Roo.menu.TextItem({ text : text }));
35751 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35752 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35753 * @param {Roo.menu.Item} item The menu item to add
35754 * @return {Roo.menu.Item} The menu item that was added
35756 insert : function(index, item){
35757 this.items.insert(index, item);
35759 var li = document.createElement("li");
35760 li.className = "x-menu-list-item";
35761 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35762 item.render(li, this);
35763 this.delayAutoWidth();
35769 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35770 * @param {Roo.menu.Item} item The menu item to remove
35772 remove : function(item){
35773 this.items.removeKey(item.id);
35778 * Removes and destroys all items in the menu
35780 removeAll : function(){
35782 while(f = this.items.first()){
35788 // MenuNav is a private utility class used internally by the Menu
35789 Roo.menu.MenuNav = function(menu){
35790 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35791 this.scope = this.menu = menu;
35794 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35795 doRelay : function(e, h){
35796 var k = e.getKey();
35797 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35798 this.menu.tryActivate(0, 1);
35801 return h.call(this.scope || this, e, this.menu);
35804 up : function(e, m){
35805 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35806 m.tryActivate(m.items.length-1, -1);
35810 down : function(e, m){
35811 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35812 m.tryActivate(0, 1);
35816 right : function(e, m){
35818 m.activeItem.expandMenu(true);
35822 left : function(e, m){
35824 if(m.parentMenu && m.parentMenu.activeItem){
35825 m.parentMenu.activeItem.activate();
35829 enter : function(e, m){
35831 e.stopPropagation();
35832 m.activeItem.onClick(e);
35833 m.fireEvent("click", this, m.activeItem);
35839 * Ext JS Library 1.1.1
35840 * Copyright(c) 2006-2007, Ext JS, LLC.
35842 * Originally Released Under LGPL - original licence link has changed is not relivant.
35845 * <script type="text/javascript">
35849 * @class Roo.menu.MenuMgr
35850 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35853 Roo.menu.MenuMgr = function(){
35854 var menus, active, groups = {}, attached = false, lastShow = new Date();
35856 // private - called when first menu is created
35859 active = new Roo.util.MixedCollection();
35860 Roo.get(document).addKeyListener(27, function(){
35861 if(active.length > 0){
35868 function hideAll(){
35869 if(active && active.length > 0){
35870 var c = active.clone();
35871 c.each(function(m){
35878 function onHide(m){
35880 if(active.length < 1){
35881 Roo.get(document).un("mousedown", onMouseDown);
35887 function onShow(m){
35888 var last = active.last();
35889 lastShow = new Date();
35892 Roo.get(document).on("mousedown", onMouseDown);
35896 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35897 m.parentMenu.activeChild = m;
35898 }else if(last && last.isVisible()){
35899 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35904 function onBeforeHide(m){
35906 m.activeChild.hide();
35908 if(m.autoHideTimer){
35909 clearTimeout(m.autoHideTimer);
35910 delete m.autoHideTimer;
35915 function onBeforeShow(m){
35916 var pm = m.parentMenu;
35917 if(!pm && !m.allowOtherMenus){
35919 }else if(pm && pm.activeChild && active != m){
35920 pm.activeChild.hide();
35925 function onMouseDown(e){
35926 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
35932 function onBeforeCheck(mi, state){
35934 var g = groups[mi.group];
35935 for(var i = 0, l = g.length; i < l; i++){
35937 g[i].setChecked(false);
35946 * Hides all menus that are currently visible
35948 hideAll : function(){
35953 register : function(menu){
35957 menus[menu.id] = menu;
35958 menu.on("beforehide", onBeforeHide);
35959 menu.on("hide", onHide);
35960 menu.on("beforeshow", onBeforeShow);
35961 menu.on("show", onShow);
35962 var g = menu.group;
35963 if(g && menu.events["checkchange"]){
35967 groups[g].push(menu);
35968 menu.on("checkchange", onCheck);
35973 * Returns a {@link Roo.menu.Menu} object
35974 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
35975 * be used to generate and return a new Menu instance.
35977 get : function(menu){
35978 if(typeof menu == "string"){ // menu id
35979 return menus[menu];
35980 }else if(menu.events){ // menu instance
35982 }else if(typeof menu.length == 'number'){ // array of menu items?
35983 return new Roo.menu.Menu({items:menu});
35984 }else{ // otherwise, must be a config
35985 return new Roo.menu.Menu(menu);
35990 unregister : function(menu){
35991 delete menus[menu.id];
35992 menu.un("beforehide", onBeforeHide);
35993 menu.un("hide", onHide);
35994 menu.un("beforeshow", onBeforeShow);
35995 menu.un("show", onShow);
35996 var g = menu.group;
35997 if(g && menu.events["checkchange"]){
35998 groups[g].remove(menu);
35999 menu.un("checkchange", onCheck);
36004 registerCheckable : function(menuItem){
36005 var g = menuItem.group;
36010 groups[g].push(menuItem);
36011 menuItem.on("beforecheckchange", onBeforeCheck);
36016 unregisterCheckable : function(menuItem){
36017 var g = menuItem.group;
36019 groups[g].remove(menuItem);
36020 menuItem.un("beforecheckchange", onBeforeCheck);
36026 * Ext JS Library 1.1.1
36027 * Copyright(c) 2006-2007, Ext JS, LLC.
36029 * Originally Released Under LGPL - original licence link has changed is not relivant.
36032 * <script type="text/javascript">
36037 * @class Roo.menu.BaseItem
36038 * @extends Roo.Component
36039 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36040 * management and base configuration options shared by all menu components.
36042 * Creates a new BaseItem
36043 * @param {Object} config Configuration options
36045 Roo.menu.BaseItem = function(config){
36046 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36051 * Fires when this item is clicked
36052 * @param {Roo.menu.BaseItem} this
36053 * @param {Roo.EventObject} e
36058 * Fires when this item is activated
36059 * @param {Roo.menu.BaseItem} this
36063 * @event deactivate
36064 * Fires when this item is deactivated
36065 * @param {Roo.menu.BaseItem} this
36071 this.on("click", this.handler, this.scope, true);
36075 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36077 * @cfg {Function} handler
36078 * A function that will handle the click event of this menu item (defaults to undefined)
36081 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36083 canActivate : false,
36086 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36091 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36093 activeClass : "x-menu-item-active",
36095 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36097 hideOnClick : true,
36099 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36104 ctype: "Roo.menu.BaseItem",
36107 actionMode : "container",
36110 render : function(container, parentMenu){
36111 this.parentMenu = parentMenu;
36112 Roo.menu.BaseItem.superclass.render.call(this, container);
36113 this.container.menuItemId = this.id;
36117 onRender : function(container, position){
36118 this.el = Roo.get(this.el);
36119 container.dom.appendChild(this.el.dom);
36123 onClick : function(e){
36124 if(!this.disabled && this.fireEvent("click", this, e) !== false
36125 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36126 this.handleClick(e);
36133 activate : function(){
36137 var li = this.container;
36138 li.addClass(this.activeClass);
36139 this.region = li.getRegion().adjust(2, 2, -2, -2);
36140 this.fireEvent("activate", this);
36145 deactivate : function(){
36146 this.container.removeClass(this.activeClass);
36147 this.fireEvent("deactivate", this);
36151 shouldDeactivate : function(e){
36152 return !this.region || !this.region.contains(e.getPoint());
36156 handleClick : function(e){
36157 if(this.hideOnClick){
36158 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36163 expandMenu : function(autoActivate){
36168 hideMenu : function(){
36173 * Ext JS Library 1.1.1
36174 * Copyright(c) 2006-2007, Ext JS, LLC.
36176 * Originally Released Under LGPL - original licence link has changed is not relivant.
36179 * <script type="text/javascript">
36183 * @class Roo.menu.Adapter
36184 * @extends Roo.menu.BaseItem
36185 * 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.
36186 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36188 * Creates a new Adapter
36189 * @param {Object} config Configuration options
36191 Roo.menu.Adapter = function(component, config){
36192 Roo.menu.Adapter.superclass.constructor.call(this, config);
36193 this.component = component;
36195 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36197 canActivate : true,
36200 onRender : function(container, position){
36201 this.component.render(container);
36202 this.el = this.component.getEl();
36206 activate : function(){
36210 this.component.focus();
36211 this.fireEvent("activate", this);
36216 deactivate : function(){
36217 this.fireEvent("deactivate", this);
36221 disable : function(){
36222 this.component.disable();
36223 Roo.menu.Adapter.superclass.disable.call(this);
36227 enable : function(){
36228 this.component.enable();
36229 Roo.menu.Adapter.superclass.enable.call(this);
36233 * Ext JS Library 1.1.1
36234 * Copyright(c) 2006-2007, Ext JS, LLC.
36236 * Originally Released Under LGPL - original licence link has changed is not relivant.
36239 * <script type="text/javascript">
36243 * @class Roo.menu.TextItem
36244 * @extends Roo.menu.BaseItem
36245 * Adds a static text string to a menu, usually used as either a heading or group separator.
36246 * Note: old style constructor with text is still supported.
36249 * Creates a new TextItem
36250 * @param {Object} cfg Configuration
36252 Roo.menu.TextItem = function(cfg){
36253 if (typeof(cfg) == 'string') {
36256 Roo.apply(this,cfg);
36259 Roo.menu.TextItem.superclass.constructor.call(this);
36262 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36264 * @cfg {Boolean} text Text to show on item.
36269 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36271 hideOnClick : false,
36273 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36275 itemCls : "x-menu-text",
36278 onRender : function(){
36279 var s = document.createElement("span");
36280 s.className = this.itemCls;
36281 s.innerHTML = this.text;
36283 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36287 * Ext JS Library 1.1.1
36288 * Copyright(c) 2006-2007, Ext JS, LLC.
36290 * Originally Released Under LGPL - original licence link has changed is not relivant.
36293 * <script type="text/javascript">
36297 * @class Roo.menu.Separator
36298 * @extends Roo.menu.BaseItem
36299 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36300 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36302 * @param {Object} config Configuration options
36304 Roo.menu.Separator = function(config){
36305 Roo.menu.Separator.superclass.constructor.call(this, config);
36308 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36310 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36312 itemCls : "x-menu-sep",
36314 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36316 hideOnClick : false,
36319 onRender : function(li){
36320 var s = document.createElement("span");
36321 s.className = this.itemCls;
36322 s.innerHTML = " ";
36324 li.addClass("x-menu-sep-li");
36325 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36329 * Ext JS Library 1.1.1
36330 * Copyright(c) 2006-2007, Ext JS, LLC.
36332 * Originally Released Under LGPL - original licence link has changed is not relivant.
36335 * <script type="text/javascript">
36338 * @class Roo.menu.Item
36339 * @extends Roo.menu.BaseItem
36340 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36341 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36342 * activation and click handling.
36344 * Creates a new Item
36345 * @param {Object} config Configuration options
36347 Roo.menu.Item = function(config){
36348 Roo.menu.Item.superclass.constructor.call(this, config);
36350 this.menu = Roo.menu.MenuMgr.get(this.menu);
36353 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36356 * @cfg {String} text
36357 * The text to show on the menu item.
36361 * @cfg {String} HTML to render in menu
36362 * The text to show on the menu item (HTML version).
36366 * @cfg {String} icon
36367 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36371 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36373 itemCls : "x-menu-item",
36375 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36377 canActivate : true,
36379 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36382 // doc'd in BaseItem
36386 ctype: "Roo.menu.Item",
36389 onRender : function(container, position){
36390 var el = document.createElement("a");
36391 el.hideFocus = true;
36392 el.unselectable = "on";
36393 el.href = this.href || "#";
36394 if(this.hrefTarget){
36395 el.target = this.hrefTarget;
36397 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36399 var html = this.html.length ? this.html : String.format('{0}',this.text);
36401 el.innerHTML = String.format(
36402 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36403 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36405 Roo.menu.Item.superclass.onRender.call(this, container, position);
36409 * Sets the text to display in this menu item
36410 * @param {String} text The text to display
36411 * @param {Boolean} isHTML true to indicate text is pure html.
36413 setText : function(text, isHTML){
36421 var html = this.html.length ? this.html : String.format('{0}',this.text);
36423 this.el.update(String.format(
36424 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36425 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36426 this.parentMenu.autoWidth();
36431 handleClick : function(e){
36432 if(!this.href){ // if no link defined, stop the event automatically
36435 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36439 activate : function(autoExpand){
36440 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36450 shouldDeactivate : function(e){
36451 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36452 if(this.menu && this.menu.isVisible()){
36453 return !this.menu.getEl().getRegion().contains(e.getPoint());
36461 deactivate : function(){
36462 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36467 expandMenu : function(autoActivate){
36468 if(!this.disabled && this.menu){
36469 clearTimeout(this.hideTimer);
36470 delete this.hideTimer;
36471 if(!this.menu.isVisible() && !this.showTimer){
36472 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36473 }else if (this.menu.isVisible() && autoActivate){
36474 this.menu.tryActivate(0, 1);
36480 deferExpand : function(autoActivate){
36481 delete this.showTimer;
36482 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36484 this.menu.tryActivate(0, 1);
36489 hideMenu : function(){
36490 clearTimeout(this.showTimer);
36491 delete this.showTimer;
36492 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36493 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36498 deferHide : function(){
36499 delete this.hideTimer;
36504 * Ext JS Library 1.1.1
36505 * Copyright(c) 2006-2007, Ext JS, LLC.
36507 * Originally Released Under LGPL - original licence link has changed is not relivant.
36510 * <script type="text/javascript">
36514 * @class Roo.menu.CheckItem
36515 * @extends Roo.menu.Item
36516 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36518 * Creates a new CheckItem
36519 * @param {Object} config Configuration options
36521 Roo.menu.CheckItem = function(config){
36522 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36525 * @event beforecheckchange
36526 * Fires before the checked value is set, providing an opportunity to cancel if needed
36527 * @param {Roo.menu.CheckItem} this
36528 * @param {Boolean} checked The new checked value that will be set
36530 "beforecheckchange" : true,
36532 * @event checkchange
36533 * Fires after the checked value has been set
36534 * @param {Roo.menu.CheckItem} this
36535 * @param {Boolean} checked The checked value that was set
36537 "checkchange" : true
36539 if(this.checkHandler){
36540 this.on('checkchange', this.checkHandler, this.scope);
36543 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36545 * @cfg {String} group
36546 * All check items with the same group name will automatically be grouped into a single-select
36547 * radio button group (defaults to '')
36550 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36552 itemCls : "x-menu-item x-menu-check-item",
36554 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36556 groupClass : "x-menu-group-item",
36559 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36560 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36561 * initialized with checked = true will be rendered as checked.
36566 ctype: "Roo.menu.CheckItem",
36569 onRender : function(c){
36570 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36572 this.el.addClass(this.groupClass);
36574 Roo.menu.MenuMgr.registerCheckable(this);
36576 this.checked = false;
36577 this.setChecked(true, true);
36582 destroy : function(){
36584 Roo.menu.MenuMgr.unregisterCheckable(this);
36586 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36590 * Set the checked state of this item
36591 * @param {Boolean} checked The new checked value
36592 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36594 setChecked : function(state, suppressEvent){
36595 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36596 if(this.container){
36597 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36599 this.checked = state;
36600 if(suppressEvent !== true){
36601 this.fireEvent("checkchange", this, state);
36607 handleClick : function(e){
36608 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36609 this.setChecked(!this.checked);
36611 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36615 * Ext JS Library 1.1.1
36616 * Copyright(c) 2006-2007, Ext JS, LLC.
36618 * Originally Released Under LGPL - original licence link has changed is not relivant.
36621 * <script type="text/javascript">
36625 * @class Roo.menu.DateItem
36626 * @extends Roo.menu.Adapter
36627 * A menu item that wraps the {@link Roo.DatPicker} component.
36629 * Creates a new DateItem
36630 * @param {Object} config Configuration options
36632 Roo.menu.DateItem = function(config){
36633 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36634 /** The Roo.DatePicker object @type Roo.DatePicker */
36635 this.picker = this.component;
36636 this.addEvents({select: true});
36638 this.picker.on("render", function(picker){
36639 picker.getEl().swallowEvent("click");
36640 picker.container.addClass("x-menu-date-item");
36643 this.picker.on("select", this.onSelect, this);
36646 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36648 onSelect : function(picker, date){
36649 this.fireEvent("select", this, date, picker);
36650 Roo.menu.DateItem.superclass.handleClick.call(this);
36654 * Ext JS Library 1.1.1
36655 * Copyright(c) 2006-2007, Ext JS, LLC.
36657 * Originally Released Under LGPL - original licence link has changed is not relivant.
36660 * <script type="text/javascript">
36664 * @class Roo.menu.ColorItem
36665 * @extends Roo.menu.Adapter
36666 * A menu item that wraps the {@link Roo.ColorPalette} component.
36668 * Creates a new ColorItem
36669 * @param {Object} config Configuration options
36671 Roo.menu.ColorItem = function(config){
36672 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36673 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36674 this.palette = this.component;
36675 this.relayEvents(this.palette, ["select"]);
36676 if(this.selectHandler){
36677 this.on('select', this.selectHandler, this.scope);
36680 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36682 * Ext JS Library 1.1.1
36683 * Copyright(c) 2006-2007, Ext JS, LLC.
36685 * Originally Released Under LGPL - original licence link has changed is not relivant.
36688 * <script type="text/javascript">
36693 * @class Roo.menu.DateMenu
36694 * @extends Roo.menu.Menu
36695 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36697 * Creates a new DateMenu
36698 * @param {Object} config Configuration options
36700 Roo.menu.DateMenu = function(config){
36701 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36703 var di = new Roo.menu.DateItem(config);
36706 * The {@link Roo.DatePicker} instance for this DateMenu
36709 this.picker = di.picker;
36712 * @param {DatePicker} picker
36713 * @param {Date} date
36715 this.relayEvents(di, ["select"]);
36716 this.on('beforeshow', function(){
36718 this.picker.hideMonthPicker(false);
36722 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36726 * Ext JS Library 1.1.1
36727 * Copyright(c) 2006-2007, Ext JS, LLC.
36729 * Originally Released Under LGPL - original licence link has changed is not relivant.
36732 * <script type="text/javascript">
36737 * @class Roo.menu.ColorMenu
36738 * @extends Roo.menu.Menu
36739 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36741 * Creates a new ColorMenu
36742 * @param {Object} config Configuration options
36744 Roo.menu.ColorMenu = function(config){
36745 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36747 var ci = new Roo.menu.ColorItem(config);
36750 * The {@link Roo.ColorPalette} instance for this ColorMenu
36751 * @type ColorPalette
36753 this.palette = ci.palette;
36756 * @param {ColorPalette} palette
36757 * @param {String} color
36759 this.relayEvents(ci, ["select"]);
36761 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36763 * Ext JS Library 1.1.1
36764 * Copyright(c) 2006-2007, Ext JS, LLC.
36766 * Originally Released Under LGPL - original licence link has changed is not relivant.
36769 * <script type="text/javascript">
36773 * @class Roo.form.Field
36774 * @extends Roo.BoxComponent
36775 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36777 * Creates a new Field
36778 * @param {Object} config Configuration options
36780 Roo.form.Field = function(config){
36781 Roo.form.Field.superclass.constructor.call(this, config);
36784 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36786 * @cfg {String} fieldLabel Label to use when rendering a form.
36789 * @cfg {String} qtip Mouse over tip
36793 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36795 invalidClass : "x-form-invalid",
36797 * @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")
36799 invalidText : "The value in this field is invalid",
36801 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36803 focusClass : "x-form-focus",
36805 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36806 automatic validation (defaults to "keyup").
36808 validationEvent : "keyup",
36810 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36812 validateOnBlur : true,
36814 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36816 validationDelay : 250,
36818 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36819 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36821 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36823 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36825 fieldClass : "x-form-field",
36827 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36830 ----------- ----------------------------------------------------------------------
36831 qtip Display a quick tip when the user hovers over the field
36832 title Display a default browser title attribute popup
36833 under Add a block div beneath the field containing the error text
36834 side Add an error icon to the right of the field with a popup on hover
36835 [element id] Add the error text directly to the innerHTML of the specified element
36838 msgTarget : 'qtip',
36840 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36845 * @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.
36850 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36855 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36857 inputType : undefined,
36860 * @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).
36862 tabIndex : undefined,
36865 isFormField : true,
36870 * @property {Roo.Element} fieldEl
36871 * Element Containing the rendered Field (with label etc.)
36874 * @cfg {Mixed} value A value to initialize this field with.
36879 * @cfg {String} name The field's HTML name attribute.
36882 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36886 initComponent : function(){
36887 Roo.form.Field.superclass.initComponent.call(this);
36891 * Fires when this field receives input focus.
36892 * @param {Roo.form.Field} this
36897 * Fires when this field loses input focus.
36898 * @param {Roo.form.Field} this
36902 * @event specialkey
36903 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36904 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36905 * @param {Roo.form.Field} this
36906 * @param {Roo.EventObject} e The event object
36911 * Fires just before the field blurs if the field value has changed.
36912 * @param {Roo.form.Field} this
36913 * @param {Mixed} newValue The new value
36914 * @param {Mixed} oldValue The original value
36919 * Fires after the field has been marked as invalid.
36920 * @param {Roo.form.Field} this
36921 * @param {String} msg The validation message
36926 * Fires after the field has been validated with no errors.
36927 * @param {Roo.form.Field} this
36932 * Fires after the key up
36933 * @param {Roo.form.Field} this
36934 * @param {Roo.EventObject} e The event Object
36941 * Returns the name attribute of the field if available
36942 * @return {String} name The field name
36944 getName: function(){
36945 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
36949 onRender : function(ct, position){
36950 Roo.form.Field.superclass.onRender.call(this, ct, position);
36952 var cfg = this.getAutoCreate();
36954 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
36956 if (!cfg.name.length) {
36959 if(this.inputType){
36960 cfg.type = this.inputType;
36962 this.el = ct.createChild(cfg, position);
36964 var type = this.el.dom.type;
36966 if(type == 'password'){
36969 this.el.addClass('x-form-'+type);
36972 this.el.dom.readOnly = true;
36974 if(this.tabIndex !== undefined){
36975 this.el.dom.setAttribute('tabIndex', this.tabIndex);
36978 this.el.addClass([this.fieldClass, this.cls]);
36983 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
36984 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
36985 * @return {Roo.form.Field} this
36987 applyTo : function(target){
36988 this.allowDomMove = false;
36989 this.el = Roo.get(target);
36990 this.render(this.el.dom.parentNode);
36995 initValue : function(){
36996 if(this.value !== undefined){
36997 this.setValue(this.value);
36998 }else if(this.el.dom.value.length > 0){
36999 this.setValue(this.el.dom.value);
37004 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37006 isDirty : function() {
37007 if(this.disabled) {
37010 return String(this.getValue()) !== String(this.originalValue);
37014 afterRender : function(){
37015 Roo.form.Field.superclass.afterRender.call(this);
37020 fireKey : function(e){
37021 //Roo.log('field ' + e.getKey());
37022 if(e.isNavKeyPress()){
37023 this.fireEvent("specialkey", this, e);
37028 * Resets the current field value to the originally loaded value and clears any validation messages
37030 reset : function(){
37031 this.setValue(this.originalValue);
37032 this.clearInvalid();
37036 initEvents : function(){
37037 // safari killled keypress - so keydown is now used..
37038 this.el.on("keydown" , this.fireKey, this);
37039 this.el.on("focus", this.onFocus, this);
37040 this.el.on("blur", this.onBlur, this);
37041 this.el.relayEvent('keyup', this);
37043 // reference to original value for reset
37044 this.originalValue = this.getValue();
37048 onFocus : function(){
37049 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37050 this.el.addClass(this.focusClass);
37052 if(!this.hasFocus){
37053 this.hasFocus = true;
37054 this.startValue = this.getValue();
37055 this.fireEvent("focus", this);
37059 beforeBlur : Roo.emptyFn,
37062 onBlur : function(){
37064 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37065 this.el.removeClass(this.focusClass);
37067 this.hasFocus = false;
37068 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37071 var v = this.getValue();
37072 if(String(v) !== String(this.startValue)){
37073 this.fireEvent('change', this, v, this.startValue);
37075 this.fireEvent("blur", this);
37079 * Returns whether or not the field value is currently valid
37080 * @param {Boolean} preventMark True to disable marking the field invalid
37081 * @return {Boolean} True if the value is valid, else false
37083 isValid : function(preventMark){
37087 var restore = this.preventMark;
37088 this.preventMark = preventMark === true;
37089 var v = this.validateValue(this.processValue(this.getRawValue()));
37090 this.preventMark = restore;
37095 * Validates the field value
37096 * @return {Boolean} True if the value is valid, else false
37098 validate : function(){
37099 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37100 this.clearInvalid();
37106 processValue : function(value){
37111 // Subclasses should provide the validation implementation by overriding this
37112 validateValue : function(value){
37117 * Mark this field as invalid
37118 * @param {String} msg The validation message
37120 markInvalid : function(msg){
37121 if(!this.rendered || this.preventMark){ // not rendered
37124 this.el.addClass(this.invalidClass);
37125 msg = msg || this.invalidText;
37126 switch(this.msgTarget){
37128 this.el.dom.qtip = msg;
37129 this.el.dom.qclass = 'x-form-invalid-tip';
37130 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37131 Roo.QuickTips.enable();
37135 this.el.dom.title = msg;
37139 var elp = this.el.findParent('.x-form-element', 5, true);
37140 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37141 this.errorEl.setWidth(elp.getWidth(true)-20);
37143 this.errorEl.update(msg);
37144 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37147 if(!this.errorIcon){
37148 var elp = this.el.findParent('.x-form-element', 5, true);
37149 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37151 this.alignErrorIcon();
37152 this.errorIcon.dom.qtip = msg;
37153 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37154 this.errorIcon.show();
37155 this.on('resize', this.alignErrorIcon, this);
37158 var t = Roo.getDom(this.msgTarget);
37160 t.style.display = this.msgDisplay;
37163 this.fireEvent('invalid', this, msg);
37167 alignErrorIcon : function(){
37168 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37172 * Clear any invalid styles/messages for this field
37174 clearInvalid : function(){
37175 if(!this.rendered || this.preventMark){ // not rendered
37178 this.el.removeClass(this.invalidClass);
37179 switch(this.msgTarget){
37181 this.el.dom.qtip = '';
37184 this.el.dom.title = '';
37188 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37192 if(this.errorIcon){
37193 this.errorIcon.dom.qtip = '';
37194 this.errorIcon.hide();
37195 this.un('resize', this.alignErrorIcon, this);
37199 var t = Roo.getDom(this.msgTarget);
37201 t.style.display = 'none';
37204 this.fireEvent('valid', this);
37208 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37209 * @return {Mixed} value The field value
37211 getRawValue : function(){
37212 var v = this.el.getValue();
37218 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37219 * @return {Mixed} value The field value
37221 getValue : function(){
37222 var v = this.el.getValue();
37228 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37229 * @param {Mixed} value The value to set
37231 setRawValue : function(v){
37232 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37236 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37237 * @param {Mixed} value The value to set
37239 setValue : function(v){
37242 this.el.dom.value = (v === null || v === undefined ? '' : v);
37247 adjustSize : function(w, h){
37248 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37249 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37253 adjustWidth : function(tag, w){
37254 tag = tag.toLowerCase();
37255 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37256 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37257 if(tag == 'input'){
37260 if(tag == 'textarea'){
37263 }else if(Roo.isOpera){
37264 if(tag == 'input'){
37267 if(tag == 'textarea'){
37277 // anything other than normal should be considered experimental
37278 Roo.form.Field.msgFx = {
37280 show: function(msgEl, f){
37281 msgEl.setDisplayed('block');
37284 hide : function(msgEl, f){
37285 msgEl.setDisplayed(false).update('');
37290 show: function(msgEl, f){
37291 msgEl.slideIn('t', {stopFx:true});
37294 hide : function(msgEl, f){
37295 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37300 show: function(msgEl, f){
37301 msgEl.fixDisplay();
37302 msgEl.alignTo(f.el, 'tl-tr');
37303 msgEl.slideIn('l', {stopFx:true});
37306 hide : function(msgEl, f){
37307 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37312 * Ext JS Library 1.1.1
37313 * Copyright(c) 2006-2007, Ext JS, LLC.
37315 * Originally Released Under LGPL - original licence link has changed is not relivant.
37318 * <script type="text/javascript">
37323 * @class Roo.form.TextField
37324 * @extends Roo.form.Field
37325 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37326 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37328 * Creates a new TextField
37329 * @param {Object} config Configuration options
37331 Roo.form.TextField = function(config){
37332 Roo.form.TextField.superclass.constructor.call(this, config);
37336 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37337 * according to the default logic, but this event provides a hook for the developer to apply additional
37338 * logic at runtime to resize the field if needed.
37339 * @param {Roo.form.Field} this This text field
37340 * @param {Number} width The new field width
37346 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37348 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37352 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37356 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37360 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37364 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37368 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37370 disableKeyFilter : false,
37372 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37376 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37380 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37382 maxLength : Number.MAX_VALUE,
37384 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37386 minLengthText : "The minimum length for this field is {0}",
37388 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37390 maxLengthText : "The maximum length for this field is {0}",
37392 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37394 selectOnFocus : false,
37396 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37398 blankText : "This field is required",
37400 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37401 * If available, this function will be called only after the basic validators all return true, and will be passed the
37402 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37406 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37407 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37408 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37412 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37416 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37422 initEvents : function()
37424 if (this.emptyText) {
37425 this.el.attr('placeholder', this.emptyText);
37428 Roo.form.TextField.superclass.initEvents.call(this);
37429 if(this.validationEvent == 'keyup'){
37430 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37431 this.el.on('keyup', this.filterValidation, this);
37433 else if(this.validationEvent !== false){
37434 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37437 if(this.selectOnFocus){
37438 this.on("focus", this.preFocus, this);
37441 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37442 this.el.on("keypress", this.filterKeys, this);
37445 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37446 this.el.on("click", this.autoSize, this);
37448 if(this.el.is('input[type=password]') && Roo.isSafari){
37449 this.el.on('keydown', this.SafariOnKeyDown, this);
37453 processValue : function(value){
37454 if(this.stripCharsRe){
37455 var newValue = value.replace(this.stripCharsRe, '');
37456 if(newValue !== value){
37457 this.setRawValue(newValue);
37464 filterValidation : function(e){
37465 if(!e.isNavKeyPress()){
37466 this.validationTask.delay(this.validationDelay);
37471 onKeyUp : function(e){
37472 if(!e.isNavKeyPress()){
37478 * Resets the current field value to the originally-loaded value and clears any validation messages.
37481 reset : function(){
37482 Roo.form.TextField.superclass.reset.call(this);
37488 preFocus : function(){
37490 if(this.selectOnFocus){
37491 this.el.dom.select();
37497 filterKeys : function(e){
37498 var k = e.getKey();
37499 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37502 var c = e.getCharCode(), cc = String.fromCharCode(c);
37503 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37506 if(!this.maskRe.test(cc)){
37511 setValue : function(v){
37513 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37519 * Validates a value according to the field's validation rules and marks the field as invalid
37520 * if the validation fails
37521 * @param {Mixed} value The value to validate
37522 * @return {Boolean} True if the value is valid, else false
37524 validateValue : function(value){
37525 if(value.length < 1) { // if it's blank
37526 if(this.allowBlank){
37527 this.clearInvalid();
37530 this.markInvalid(this.blankText);
37534 if(value.length < this.minLength){
37535 this.markInvalid(String.format(this.minLengthText, this.minLength));
37538 if(value.length > this.maxLength){
37539 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37543 var vt = Roo.form.VTypes;
37544 if(!vt[this.vtype](value, this)){
37545 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37549 if(typeof this.validator == "function"){
37550 var msg = this.validator(value);
37552 this.markInvalid(msg);
37556 if(this.regex && !this.regex.test(value)){
37557 this.markInvalid(this.regexText);
37564 * Selects text in this field
37565 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37566 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37568 selectText : function(start, end){
37569 var v = this.getRawValue();
37571 start = start === undefined ? 0 : start;
37572 end = end === undefined ? v.length : end;
37573 var d = this.el.dom;
37574 if(d.setSelectionRange){
37575 d.setSelectionRange(start, end);
37576 }else if(d.createTextRange){
37577 var range = d.createTextRange();
37578 range.moveStart("character", start);
37579 range.moveEnd("character", v.length-end);
37586 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37587 * This only takes effect if grow = true, and fires the autosize event.
37589 autoSize : function(){
37590 if(!this.grow || !this.rendered){
37594 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37597 var v = el.dom.value;
37598 var d = document.createElement('div');
37599 d.appendChild(document.createTextNode(v));
37603 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37604 this.el.setWidth(w);
37605 this.fireEvent("autosize", this, w);
37609 SafariOnKeyDown : function(event)
37611 // this is a workaround for a password hang bug on chrome/ webkit.
37613 var isSelectAll = false;
37615 if(this.el.dom.selectionEnd > 0){
37616 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37618 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37619 event.preventDefault();
37624 if(isSelectAll){ // backspace and delete key
37626 event.preventDefault();
37627 // this is very hacky as keydown always get's upper case.
37629 var cc = String.fromCharCode(event.getCharCode());
37630 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37638 * Ext JS Library 1.1.1
37639 * Copyright(c) 2006-2007, Ext JS, LLC.
37641 * Originally Released Under LGPL - original licence link has changed is not relivant.
37644 * <script type="text/javascript">
37648 * @class Roo.form.Hidden
37649 * @extends Roo.form.TextField
37650 * Simple Hidden element used on forms
37652 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37655 * Creates a new Hidden form element.
37656 * @param {Object} config Configuration options
37661 // easy hidden field...
37662 Roo.form.Hidden = function(config){
37663 Roo.form.Hidden.superclass.constructor.call(this, config);
37666 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37668 inputType: 'hidden',
37671 labelSeparator: '',
37673 itemCls : 'x-form-item-display-none'
37681 * Ext JS Library 1.1.1
37682 * Copyright(c) 2006-2007, Ext JS, LLC.
37684 * Originally Released Under LGPL - original licence link has changed is not relivant.
37687 * <script type="text/javascript">
37691 * @class Roo.form.TriggerField
37692 * @extends Roo.form.TextField
37693 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37694 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37695 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37696 * for which you can provide a custom implementation. For example:
37698 var trigger = new Roo.form.TriggerField();
37699 trigger.onTriggerClick = myTriggerFn;
37700 trigger.applyTo('my-field');
37703 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37704 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37705 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37706 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37708 * Create a new TriggerField.
37709 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37710 * to the base TextField)
37712 Roo.form.TriggerField = function(config){
37713 this.mimicing = false;
37714 Roo.form.TriggerField.superclass.constructor.call(this, config);
37717 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37719 * @cfg {String} triggerClass A CSS class to apply to the trigger
37722 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37723 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37725 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37727 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37731 /** @cfg {Boolean} grow @hide */
37732 /** @cfg {Number} growMin @hide */
37733 /** @cfg {Number} growMax @hide */
37739 autoSize: Roo.emptyFn,
37743 deferHeight : true,
37746 actionMode : 'wrap',
37748 onResize : function(w, h){
37749 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37750 if(typeof w == 'number'){
37751 var x = w - this.trigger.getWidth();
37752 this.el.setWidth(this.adjustWidth('input', x));
37753 this.trigger.setStyle('left', x+'px');
37758 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37761 getResizeEl : function(){
37766 getPositionEl : function(){
37771 alignErrorIcon : function(){
37772 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37776 onRender : function(ct, position){
37777 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37778 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37779 this.trigger = this.wrap.createChild(this.triggerConfig ||
37780 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37781 if(this.hideTrigger){
37782 this.trigger.setDisplayed(false);
37784 this.initTrigger();
37786 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37791 initTrigger : function(){
37792 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37793 this.trigger.addClassOnOver('x-form-trigger-over');
37794 this.trigger.addClassOnClick('x-form-trigger-click');
37798 onDestroy : function(){
37800 this.trigger.removeAllListeners();
37801 this.trigger.remove();
37804 this.wrap.remove();
37806 Roo.form.TriggerField.superclass.onDestroy.call(this);
37810 onFocus : function(){
37811 Roo.form.TriggerField.superclass.onFocus.call(this);
37812 if(!this.mimicing){
37813 this.wrap.addClass('x-trigger-wrap-focus');
37814 this.mimicing = true;
37815 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37816 if(this.monitorTab){
37817 this.el.on("keydown", this.checkTab, this);
37823 checkTab : function(e){
37824 if(e.getKey() == e.TAB){
37825 this.triggerBlur();
37830 onBlur : function(){
37835 mimicBlur : function(e, t){
37836 if(!this.wrap.contains(t) && this.validateBlur()){
37837 this.triggerBlur();
37842 triggerBlur : function(){
37843 this.mimicing = false;
37844 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37845 if(this.monitorTab){
37846 this.el.un("keydown", this.checkTab, this);
37848 this.wrap.removeClass('x-trigger-wrap-focus');
37849 Roo.form.TriggerField.superclass.onBlur.call(this);
37853 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37854 validateBlur : function(e, t){
37859 onDisable : function(){
37860 Roo.form.TriggerField.superclass.onDisable.call(this);
37862 this.wrap.addClass('x-item-disabled');
37867 onEnable : function(){
37868 Roo.form.TriggerField.superclass.onEnable.call(this);
37870 this.wrap.removeClass('x-item-disabled');
37875 onShow : function(){
37876 var ae = this.getActionEl();
37879 ae.dom.style.display = '';
37880 ae.dom.style.visibility = 'visible';
37886 onHide : function(){
37887 var ae = this.getActionEl();
37888 ae.dom.style.display = 'none';
37892 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37893 * by an implementing function.
37895 * @param {EventObject} e
37897 onTriggerClick : Roo.emptyFn
37900 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37901 // to be extended by an implementing class. For an example of implementing this class, see the custom
37902 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37903 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37904 initComponent : function(){
37905 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37907 this.triggerConfig = {
37908 tag:'span', cls:'x-form-twin-triggers', cn:[
37909 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37910 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
37914 getTrigger : function(index){
37915 return this.triggers[index];
37918 initTrigger : function(){
37919 var ts = this.trigger.select('.x-form-trigger', true);
37920 this.wrap.setStyle('overflow', 'hidden');
37921 var triggerField = this;
37922 ts.each(function(t, all, index){
37923 t.hide = function(){
37924 var w = triggerField.wrap.getWidth();
37925 this.dom.style.display = 'none';
37926 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37928 t.show = function(){
37929 var w = triggerField.wrap.getWidth();
37930 this.dom.style.display = '';
37931 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37933 var triggerIndex = 'Trigger'+(index+1);
37935 if(this['hide'+triggerIndex]){
37936 t.dom.style.display = 'none';
37938 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
37939 t.addClassOnOver('x-form-trigger-over');
37940 t.addClassOnClick('x-form-trigger-click');
37942 this.triggers = ts.elements;
37945 onTrigger1Click : Roo.emptyFn,
37946 onTrigger2Click : Roo.emptyFn
37949 * Ext JS Library 1.1.1
37950 * Copyright(c) 2006-2007, Ext JS, LLC.
37952 * Originally Released Under LGPL - original licence link has changed is not relivant.
37955 * <script type="text/javascript">
37959 * @class Roo.form.TextArea
37960 * @extends Roo.form.TextField
37961 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
37962 * support for auto-sizing.
37964 * Creates a new TextArea
37965 * @param {Object} config Configuration options
37967 Roo.form.TextArea = function(config){
37968 Roo.form.TextArea.superclass.constructor.call(this, config);
37969 // these are provided exchanges for backwards compat
37970 // minHeight/maxHeight were replaced by growMin/growMax to be
37971 // compatible with TextField growing config values
37972 if(this.minHeight !== undefined){
37973 this.growMin = this.minHeight;
37975 if(this.maxHeight !== undefined){
37976 this.growMax = this.maxHeight;
37980 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
37982 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
37986 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
37990 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
37991 * in the field (equivalent to setting overflow: hidden, defaults to false)
37993 preventScrollbars: false,
37995 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37996 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38000 onRender : function(ct, position){
38002 this.defaultAutoCreate = {
38004 style:"width:300px;height:60px;",
38005 autocomplete: "off"
38008 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38010 this.textSizeEl = Roo.DomHelper.append(document.body, {
38011 tag: "pre", cls: "x-form-grow-sizer"
38013 if(this.preventScrollbars){
38014 this.el.setStyle("overflow", "hidden");
38016 this.el.setHeight(this.growMin);
38020 onDestroy : function(){
38021 if(this.textSizeEl){
38022 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38024 Roo.form.TextArea.superclass.onDestroy.call(this);
38028 onKeyUp : function(e){
38029 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38035 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38036 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38038 autoSize : function(){
38039 if(!this.grow || !this.textSizeEl){
38043 var v = el.dom.value;
38044 var ts = this.textSizeEl;
38047 ts.appendChild(document.createTextNode(v));
38050 Roo.fly(ts).setWidth(this.el.getWidth());
38052 v = "  ";
38055 v = v.replace(/\n/g, '<p> </p>');
38057 v += " \n ";
38060 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38061 if(h != this.lastHeight){
38062 this.lastHeight = h;
38063 this.el.setHeight(h);
38064 this.fireEvent("autosize", this, h);
38069 * Ext JS Library 1.1.1
38070 * Copyright(c) 2006-2007, Ext JS, LLC.
38072 * Originally Released Under LGPL - original licence link has changed is not relivant.
38075 * <script type="text/javascript">
38080 * @class Roo.form.NumberField
38081 * @extends Roo.form.TextField
38082 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38084 * Creates a new NumberField
38085 * @param {Object} config Configuration options
38087 Roo.form.NumberField = function(config){
38088 Roo.form.NumberField.superclass.constructor.call(this, config);
38091 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38093 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38095 fieldClass: "x-form-field x-form-num-field",
38097 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38099 allowDecimals : true,
38101 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38103 decimalSeparator : ".",
38105 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38107 decimalPrecision : 2,
38109 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38111 allowNegative : true,
38113 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38115 minValue : Number.NEGATIVE_INFINITY,
38117 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38119 maxValue : Number.MAX_VALUE,
38121 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38123 minText : "The minimum value for this field is {0}",
38125 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38127 maxText : "The maximum value for this field is {0}",
38129 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38130 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38132 nanText : "{0} is not a valid number",
38135 initEvents : function(){
38136 Roo.form.NumberField.superclass.initEvents.call(this);
38137 var allowed = "0123456789";
38138 if(this.allowDecimals){
38139 allowed += this.decimalSeparator;
38141 if(this.allowNegative){
38144 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38145 var keyPress = function(e){
38146 var k = e.getKey();
38147 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38150 var c = e.getCharCode();
38151 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38155 this.el.on("keypress", keyPress, this);
38159 validateValue : function(value){
38160 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38163 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38166 var num = this.parseValue(value);
38168 this.markInvalid(String.format(this.nanText, value));
38171 if(num < this.minValue){
38172 this.markInvalid(String.format(this.minText, this.minValue));
38175 if(num > this.maxValue){
38176 this.markInvalid(String.format(this.maxText, this.maxValue));
38182 getValue : function(){
38183 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38187 parseValue : function(value){
38188 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38189 return isNaN(value) ? '' : value;
38193 fixPrecision : function(value){
38194 var nan = isNaN(value);
38195 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38196 return nan ? '' : value;
38198 return parseFloat(value).toFixed(this.decimalPrecision);
38201 setValue : function(v){
38202 v = this.fixPrecision(v);
38203 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38207 decimalPrecisionFcn : function(v){
38208 return Math.floor(v);
38211 beforeBlur : function(){
38212 var v = this.parseValue(this.getRawValue());
38219 * Ext JS Library 1.1.1
38220 * Copyright(c) 2006-2007, Ext JS, LLC.
38222 * Originally Released Under LGPL - original licence link has changed is not relivant.
38225 * <script type="text/javascript">
38229 * @class Roo.form.DateField
38230 * @extends Roo.form.TriggerField
38231 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38233 * Create a new DateField
38234 * @param {Object} config
38236 Roo.form.DateField = function(config){
38237 Roo.form.DateField.superclass.constructor.call(this, config);
38243 * Fires when a date is selected
38244 * @param {Roo.form.DateField} combo This combo box
38245 * @param {Date} date The date selected
38252 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38253 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38254 this.ddMatch = null;
38255 if(this.disabledDates){
38256 var dd = this.disabledDates;
38258 for(var i = 0; i < dd.length; i++){
38260 if(i != dd.length-1) re += "|";
38262 this.ddMatch = new RegExp(re + ")");
38266 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38268 * @cfg {String} format
38269 * The default date format string which can be overriden for localization support. The format must be
38270 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38274 * @cfg {String} altFormats
38275 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38276 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38278 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38280 * @cfg {Array} disabledDays
38281 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38283 disabledDays : null,
38285 * @cfg {String} disabledDaysText
38286 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38288 disabledDaysText : "Disabled",
38290 * @cfg {Array} disabledDates
38291 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38292 * expression so they are very powerful. Some examples:
38294 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38295 * <li>["03/08", "09/16"] would disable those days for every year</li>
38296 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38297 * <li>["03/../2006"] would disable every day in March 2006</li>
38298 * <li>["^03"] would disable every day in every March</li>
38300 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38301 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38303 disabledDates : null,
38305 * @cfg {String} disabledDatesText
38306 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38308 disabledDatesText : "Disabled",
38310 * @cfg {Date/String} minValue
38311 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38312 * valid format (defaults to null).
38316 * @cfg {Date/String} maxValue
38317 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38318 * valid format (defaults to null).
38322 * @cfg {String} minText
38323 * The error text to display when the date in the cell is before minValue (defaults to
38324 * 'The date in this field must be after {minValue}').
38326 minText : "The date in this field must be equal to or after {0}",
38328 * @cfg {String} maxText
38329 * The error text to display when the date in the cell is after maxValue (defaults to
38330 * 'The date in this field must be before {maxValue}').
38332 maxText : "The date in this field must be equal to or before {0}",
38334 * @cfg {String} invalidText
38335 * The error text to display when the date in the field is invalid (defaults to
38336 * '{value} is not a valid date - it must be in the format {format}').
38338 invalidText : "{0} is not a valid date - it must be in the format {1}",
38340 * @cfg {String} triggerClass
38341 * An additional CSS class used to style the trigger button. The trigger will always get the
38342 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38343 * which displays a calendar icon).
38345 triggerClass : 'x-form-date-trigger',
38349 * @cfg {Boolean} useIso
38350 * if enabled, then the date field will use a hidden field to store the
38351 * real value as iso formated date. default (false)
38355 * @cfg {String/Object} autoCreate
38356 * A DomHelper element spec, or true for a default element spec (defaults to
38357 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38360 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38363 hiddenField: false,
38365 onRender : function(ct, position)
38367 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38369 //this.el.dom.removeAttribute('name');
38370 Roo.log("Changing name?");
38371 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38372 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38374 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38375 // prevent input submission
38376 this.hiddenName = this.name;
38383 validateValue : function(value)
38385 value = this.formatDate(value);
38386 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38387 Roo.log('super failed');
38390 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38393 var svalue = value;
38394 value = this.parseDate(value);
38396 Roo.log('parse date failed' + svalue);
38397 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38400 var time = value.getTime();
38401 if(this.minValue && time < this.minValue.getTime()){
38402 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38405 if(this.maxValue && time > this.maxValue.getTime()){
38406 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38409 if(this.disabledDays){
38410 var day = value.getDay();
38411 for(var i = 0; i < this.disabledDays.length; i++) {
38412 if(day === this.disabledDays[i]){
38413 this.markInvalid(this.disabledDaysText);
38418 var fvalue = this.formatDate(value);
38419 if(this.ddMatch && this.ddMatch.test(fvalue)){
38420 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38427 // Provides logic to override the default TriggerField.validateBlur which just returns true
38428 validateBlur : function(){
38429 return !this.menu || !this.menu.isVisible();
38432 getName: function()
38434 // returns hidden if it's set..
38435 if (!this.rendered) {return ''};
38436 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38441 * Returns the current date value of the date field.
38442 * @return {Date} The date value
38444 getValue : function(){
38446 return this.hiddenField ?
38447 this.hiddenField.value :
38448 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38452 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38453 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38454 * (the default format used is "m/d/y").
38457 //All of these calls set the same date value (May 4, 2006)
38459 //Pass a date object:
38460 var dt = new Date('5/4/06');
38461 dateField.setValue(dt);
38463 //Pass a date string (default format):
38464 dateField.setValue('5/4/06');
38466 //Pass a date string (custom format):
38467 dateField.format = 'Y-m-d';
38468 dateField.setValue('2006-5-4');
38470 * @param {String/Date} date The date or valid date string
38472 setValue : function(date){
38473 if (this.hiddenField) {
38474 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38476 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38477 // make sure the value field is always stored as a date..
38478 this.value = this.parseDate(date);
38484 parseDate : function(value){
38485 if(!value || value instanceof Date){
38488 var v = Date.parseDate(value, this.format);
38489 if (!v && this.useIso) {
38490 v = Date.parseDate(value, 'Y-m-d');
38492 if(!v && this.altFormats){
38493 if(!this.altFormatsArray){
38494 this.altFormatsArray = this.altFormats.split("|");
38496 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38497 v = Date.parseDate(value, this.altFormatsArray[i]);
38504 formatDate : function(date, fmt){
38505 return (!date || !(date instanceof Date)) ?
38506 date : date.dateFormat(fmt || this.format);
38511 select: function(m, d){
38514 this.fireEvent('select', this, d);
38516 show : function(){ // retain focus styling
38520 this.focus.defer(10, this);
38521 var ml = this.menuListeners;
38522 this.menu.un("select", ml.select, this);
38523 this.menu.un("show", ml.show, this);
38524 this.menu.un("hide", ml.hide, this);
38529 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38530 onTriggerClick : function(){
38534 if(this.menu == null){
38535 this.menu = new Roo.menu.DateMenu();
38537 Roo.apply(this.menu.picker, {
38538 showClear: this.allowBlank,
38539 minDate : this.minValue,
38540 maxDate : this.maxValue,
38541 disabledDatesRE : this.ddMatch,
38542 disabledDatesText : this.disabledDatesText,
38543 disabledDays : this.disabledDays,
38544 disabledDaysText : this.disabledDaysText,
38545 format : this.useIso ? 'Y-m-d' : this.format,
38546 minText : String.format(this.minText, this.formatDate(this.minValue)),
38547 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38549 this.menu.on(Roo.apply({}, this.menuListeners, {
38552 this.menu.picker.setValue(this.getValue() || new Date());
38553 this.menu.show(this.el, "tl-bl?");
38556 beforeBlur : function(){
38557 var v = this.parseDate(this.getRawValue());
38563 /** @cfg {Boolean} grow @hide */
38564 /** @cfg {Number} growMin @hide */
38565 /** @cfg {Number} growMax @hide */
38572 * Ext JS Library 1.1.1
38573 * Copyright(c) 2006-2007, Ext JS, LLC.
38575 * Originally Released Under LGPL - original licence link has changed is not relivant.
38578 * <script type="text/javascript">
38582 * @class Roo.form.MonthField
38583 * @extends Roo.form.TriggerField
38584 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38586 * Create a new MonthField
38587 * @param {Object} config
38589 Roo.form.MonthField = function(config){
38591 Roo.form.MonthField.superclass.constructor.call(this, config);
38597 * Fires when a date is selected
38598 * @param {Roo.form.MonthFieeld} combo This combo box
38599 * @param {Date} date The date selected
38606 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38607 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38608 this.ddMatch = null;
38609 if(this.disabledDates){
38610 var dd = this.disabledDates;
38612 for(var i = 0; i < dd.length; i++){
38614 if(i != dd.length-1) re += "|";
38616 this.ddMatch = new RegExp(re + ")");
38620 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38622 * @cfg {String} format
38623 * The default date format string which can be overriden for localization support. The format must be
38624 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38628 * @cfg {String} altFormats
38629 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38630 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38632 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38634 * @cfg {Array} disabledDays
38635 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38637 disabledDays : [0,1,2,3,4,5,6],
38639 * @cfg {String} disabledDaysText
38640 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38642 disabledDaysText : "Disabled",
38644 * @cfg {Array} disabledDates
38645 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38646 * expression so they are very powerful. Some examples:
38648 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38649 * <li>["03/08", "09/16"] would disable those days for every year</li>
38650 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38651 * <li>["03/../2006"] would disable every day in March 2006</li>
38652 * <li>["^03"] would disable every day in every March</li>
38654 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38655 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38657 disabledDates : null,
38659 * @cfg {String} disabledDatesText
38660 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38662 disabledDatesText : "Disabled",
38664 * @cfg {Date/String} minValue
38665 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38666 * valid format (defaults to null).
38670 * @cfg {Date/String} maxValue
38671 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38672 * valid format (defaults to null).
38676 * @cfg {String} minText
38677 * The error text to display when the date in the cell is before minValue (defaults to
38678 * 'The date in this field must be after {minValue}').
38680 minText : "The date in this field must be equal to or after {0}",
38682 * @cfg {String} maxTextf
38683 * The error text to display when the date in the cell is after maxValue (defaults to
38684 * 'The date in this field must be before {maxValue}').
38686 maxText : "The date in this field must be equal to or before {0}",
38688 * @cfg {String} invalidText
38689 * The error text to display when the date in the field is invalid (defaults to
38690 * '{value} is not a valid date - it must be in the format {format}').
38692 invalidText : "{0} is not a valid date - it must be in the format {1}",
38694 * @cfg {String} triggerClass
38695 * An additional CSS class used to style the trigger button. The trigger will always get the
38696 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38697 * which displays a calendar icon).
38699 triggerClass : 'x-form-date-trigger',
38703 * @cfg {Boolean} useIso
38704 * if enabled, then the date field will use a hidden field to store the
38705 * real value as iso formated date. default (true)
38709 * @cfg {String/Object} autoCreate
38710 * A DomHelper element spec, or true for a default element spec (defaults to
38711 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38714 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38717 hiddenField: false,
38719 hideMonthPicker : false,
38721 onRender : function(ct, position)
38723 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38725 this.el.dom.removeAttribute('name');
38726 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38728 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38729 // prevent input submission
38730 this.hiddenName = this.name;
38737 validateValue : function(value)
38739 value = this.formatDate(value);
38740 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38743 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38746 var svalue = value;
38747 value = this.parseDate(value);
38749 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38752 var time = value.getTime();
38753 if(this.minValue && time < this.minValue.getTime()){
38754 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38757 if(this.maxValue && time > this.maxValue.getTime()){
38758 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38761 /*if(this.disabledDays){
38762 var day = value.getDay();
38763 for(var i = 0; i < this.disabledDays.length; i++) {
38764 if(day === this.disabledDays[i]){
38765 this.markInvalid(this.disabledDaysText);
38771 var fvalue = this.formatDate(value);
38772 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38773 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38781 // Provides logic to override the default TriggerField.validateBlur which just returns true
38782 validateBlur : function(){
38783 return !this.menu || !this.menu.isVisible();
38787 * Returns the current date value of the date field.
38788 * @return {Date} The date value
38790 getValue : function(){
38794 return this.hiddenField ?
38795 this.hiddenField.value :
38796 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38800 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38801 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38802 * (the default format used is "m/d/y").
38805 //All of these calls set the same date value (May 4, 2006)
38807 //Pass a date object:
38808 var dt = new Date('5/4/06');
38809 monthField.setValue(dt);
38811 //Pass a date string (default format):
38812 monthField.setValue('5/4/06');
38814 //Pass a date string (custom format):
38815 monthField.format = 'Y-m-d';
38816 monthField.setValue('2006-5-4');
38818 * @param {String/Date} date The date or valid date string
38820 setValue : function(date){
38821 Roo.log('month setValue' + date);
38822 // can only be first of month..
38824 var val = this.parseDate(date);
38826 if (this.hiddenField) {
38827 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38829 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38830 this.value = this.parseDate(date);
38834 parseDate : function(value){
38835 if(!value || value instanceof Date){
38836 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38839 var v = Date.parseDate(value, this.format);
38840 if (!v && this.useIso) {
38841 v = Date.parseDate(value, 'Y-m-d');
38845 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38849 if(!v && this.altFormats){
38850 if(!this.altFormatsArray){
38851 this.altFormatsArray = this.altFormats.split("|");
38853 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38854 v = Date.parseDate(value, this.altFormatsArray[i]);
38861 formatDate : function(date, fmt){
38862 return (!date || !(date instanceof Date)) ?
38863 date : date.dateFormat(fmt || this.format);
38868 select: function(m, d){
38870 this.fireEvent('select', this, d);
38872 show : function(){ // retain focus styling
38876 this.focus.defer(10, this);
38877 var ml = this.menuListeners;
38878 this.menu.un("select", ml.select, this);
38879 this.menu.un("show", ml.show, this);
38880 this.menu.un("hide", ml.hide, this);
38884 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38885 onTriggerClick : function(){
38889 if(this.menu == null){
38890 this.menu = new Roo.menu.DateMenu();
38894 Roo.apply(this.menu.picker, {
38896 showClear: this.allowBlank,
38897 minDate : this.minValue,
38898 maxDate : this.maxValue,
38899 disabledDatesRE : this.ddMatch,
38900 disabledDatesText : this.disabledDatesText,
38902 format : this.useIso ? 'Y-m-d' : this.format,
38903 minText : String.format(this.minText, this.formatDate(this.minValue)),
38904 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38907 this.menu.on(Roo.apply({}, this.menuListeners, {
38915 // hide month picker get's called when we called by 'before hide';
38917 var ignorehide = true;
38918 p.hideMonthPicker = function(disableAnim){
38922 if(this.monthPicker){
38923 Roo.log("hideMonthPicker called");
38924 if(disableAnim === true){
38925 this.monthPicker.hide();
38927 this.monthPicker.slideOut('t', {duration:.2});
38928 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
38929 p.fireEvent("select", this, this.value);
38935 Roo.log('picker set value');
38936 Roo.log(this.getValue());
38937 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
38938 m.show(this.el, 'tl-bl?');
38939 ignorehide = false;
38940 // this will trigger hideMonthPicker..
38943 // hidden the day picker
38944 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
38950 p.showMonthPicker.defer(100, p);
38956 beforeBlur : function(){
38957 var v = this.parseDate(this.getRawValue());
38963 /** @cfg {Boolean} grow @hide */
38964 /** @cfg {Number} growMin @hide */
38965 /** @cfg {Number} growMax @hide */
38972 * Ext JS Library 1.1.1
38973 * Copyright(c) 2006-2007, Ext JS, LLC.
38975 * Originally Released Under LGPL - original licence link has changed is not relivant.
38978 * <script type="text/javascript">
38983 * @class Roo.form.ComboBox
38984 * @extends Roo.form.TriggerField
38985 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
38987 * Create a new ComboBox.
38988 * @param {Object} config Configuration options
38990 Roo.form.ComboBox = function(config){
38991 Roo.form.ComboBox.superclass.constructor.call(this, config);
38995 * Fires when the dropdown list is expanded
38996 * @param {Roo.form.ComboBox} combo This combo box
39001 * Fires when the dropdown list is collapsed
39002 * @param {Roo.form.ComboBox} combo This combo box
39006 * @event beforeselect
39007 * Fires before a list item is selected. Return false to cancel the selection.
39008 * @param {Roo.form.ComboBox} combo This combo box
39009 * @param {Roo.data.Record} record The data record returned from the underlying store
39010 * @param {Number} index The index of the selected item in the dropdown list
39012 'beforeselect' : true,
39015 * Fires when a list item is selected
39016 * @param {Roo.form.ComboBox} combo This combo box
39017 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39018 * @param {Number} index The index of the selected item in the dropdown list
39022 * @event beforequery
39023 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39024 * The event object passed has these properties:
39025 * @param {Roo.form.ComboBox} combo This combo box
39026 * @param {String} query The query
39027 * @param {Boolean} forceAll true to force "all" query
39028 * @param {Boolean} cancel true to cancel the query
39029 * @param {Object} e The query event object
39031 'beforequery': true,
39034 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39035 * @param {Roo.form.ComboBox} combo This combo box
39040 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39041 * @param {Roo.form.ComboBox} combo This combo box
39042 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39048 if(this.transform){
39049 this.allowDomMove = false;
39050 var s = Roo.getDom(this.transform);
39051 if(!this.hiddenName){
39052 this.hiddenName = s.name;
39055 this.mode = 'local';
39056 var d = [], opts = s.options;
39057 for(var i = 0, len = opts.length;i < len; i++){
39059 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39061 this.value = value;
39063 d.push([value, o.text]);
39065 this.store = new Roo.data.SimpleStore({
39067 fields: ['value', 'text'],
39070 this.valueField = 'value';
39071 this.displayField = 'text';
39073 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39074 if(!this.lazyRender){
39075 this.target = true;
39076 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39077 s.parentNode.removeChild(s); // remove it
39078 this.render(this.el.parentNode);
39080 s.parentNode.removeChild(s); // remove it
39085 this.store = Roo.factory(this.store, Roo.data);
39088 this.selectedIndex = -1;
39089 if(this.mode == 'local'){
39090 if(config.queryDelay === undefined){
39091 this.queryDelay = 10;
39093 if(config.minChars === undefined){
39099 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39101 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39104 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39105 * rendering into an Roo.Editor, defaults to false)
39108 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39109 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39112 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39115 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39116 * the dropdown list (defaults to undefined, with no header element)
39120 * @cfg {String/Roo.Template} tpl The template to use to render the output
39124 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39126 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39128 listWidth: undefined,
39130 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39131 * mode = 'remote' or 'text' if mode = 'local')
39133 displayField: undefined,
39135 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39136 * mode = 'remote' or 'value' if mode = 'local').
39137 * Note: use of a valueField requires the user make a selection
39138 * in order for a value to be mapped.
39140 valueField: undefined,
39144 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39145 * field's data value (defaults to the underlying DOM element's name)
39147 hiddenName: undefined,
39149 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39153 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39155 selectedClass: 'x-combo-selected',
39157 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39158 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39159 * which displays a downward arrow icon).
39161 triggerClass : 'x-form-arrow-trigger',
39163 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39167 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39168 * anchor positions (defaults to 'tl-bl')
39170 listAlign: 'tl-bl?',
39172 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39176 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39177 * query specified by the allQuery config option (defaults to 'query')
39179 triggerAction: 'query',
39181 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39182 * (defaults to 4, does not apply if editable = false)
39186 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39187 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39191 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39192 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39196 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39197 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39201 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39202 * when editable = true (defaults to false)
39204 selectOnFocus:false,
39206 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39208 queryParam: 'query',
39210 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39211 * when mode = 'remote' (defaults to 'Loading...')
39213 loadingText: 'Loading...',
39215 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39219 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39223 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39224 * traditional select (defaults to true)
39228 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39232 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39236 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39237 * listWidth has a higher value)
39241 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39242 * allow the user to set arbitrary text into the field (defaults to false)
39244 forceSelection:false,
39246 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39247 * if typeAhead = true (defaults to 250)
39249 typeAheadDelay : 250,
39251 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39252 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39254 valueNotFoundText : undefined,
39256 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39258 blockFocus : false,
39261 * @cfg {Boolean} disableClear Disable showing of clear button.
39263 disableClear : false,
39265 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39267 alwaysQuery : false,
39273 // element that contains real text value.. (when hidden is used..)
39276 onRender : function(ct, position){
39277 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39278 if(this.hiddenName){
39279 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39281 this.hiddenField.value =
39282 this.hiddenValue !== undefined ? this.hiddenValue :
39283 this.value !== undefined ? this.value : '';
39285 // prevent input submission
39286 this.el.dom.removeAttribute('name');
39291 this.el.dom.setAttribute('autocomplete', 'off');
39294 var cls = 'x-combo-list';
39296 this.list = new Roo.Layer({
39297 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39300 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39301 this.list.setWidth(lw);
39302 this.list.swallowEvent('mousewheel');
39303 this.assetHeight = 0;
39306 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39307 this.assetHeight += this.header.getHeight();
39310 this.innerList = this.list.createChild({cls:cls+'-inner'});
39311 this.innerList.on('mouseover', this.onViewOver, this);
39312 this.innerList.on('mousemove', this.onViewMove, this);
39313 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39315 if(this.allowBlank && !this.pageSize && !this.disableClear){
39316 this.footer = this.list.createChild({cls:cls+'-ft'});
39317 this.pageTb = new Roo.Toolbar(this.footer);
39321 this.footer = this.list.createChild({cls:cls+'-ft'});
39322 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39323 {pageSize: this.pageSize});
39327 if (this.pageTb && this.allowBlank && !this.disableClear) {
39329 this.pageTb.add(new Roo.Toolbar.Fill(), {
39330 cls: 'x-btn-icon x-btn-clear',
39332 handler: function()
39335 _this.clearValue();
39336 _this.onSelect(false, -1);
39341 this.assetHeight += this.footer.getHeight();
39346 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39349 this.view = new Roo.View(this.innerList, this.tpl, {
39350 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39353 this.view.on('click', this.onViewClick, this);
39355 this.store.on('beforeload', this.onBeforeLoad, this);
39356 this.store.on('load', this.onLoad, this);
39357 this.store.on('loadexception', this.onLoadException, this);
39359 if(this.resizable){
39360 this.resizer = new Roo.Resizable(this.list, {
39361 pinned:true, handles:'se'
39363 this.resizer.on('resize', function(r, w, h){
39364 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39365 this.listWidth = w;
39366 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39367 this.restrictHeight();
39369 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39371 if(!this.editable){
39372 this.editable = true;
39373 this.setEditable(false);
39377 if (typeof(this.events.add.listeners) != 'undefined') {
39379 this.addicon = this.wrap.createChild(
39380 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39382 this.addicon.on('click', function(e) {
39383 this.fireEvent('add', this);
39386 if (typeof(this.events.edit.listeners) != 'undefined') {
39388 this.editicon = this.wrap.createChild(
39389 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39390 if (this.addicon) {
39391 this.editicon.setStyle('margin-left', '40px');
39393 this.editicon.on('click', function(e) {
39395 // we fire even if inothing is selected..
39396 this.fireEvent('edit', this, this.lastData );
39406 initEvents : function(){
39407 Roo.form.ComboBox.superclass.initEvents.call(this);
39409 this.keyNav = new Roo.KeyNav(this.el, {
39410 "up" : function(e){
39411 this.inKeyMode = true;
39415 "down" : function(e){
39416 if(!this.isExpanded()){
39417 this.onTriggerClick();
39419 this.inKeyMode = true;
39424 "enter" : function(e){
39425 this.onViewClick();
39429 "esc" : function(e){
39433 "tab" : function(e){
39434 this.onViewClick(false);
39435 this.fireEvent("specialkey", this, e);
39441 doRelay : function(foo, bar, hname){
39442 if(hname == 'down' || this.scope.isExpanded()){
39443 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39450 this.queryDelay = Math.max(this.queryDelay || 10,
39451 this.mode == 'local' ? 10 : 250);
39452 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39453 if(this.typeAhead){
39454 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39456 if(this.editable !== false){
39457 this.el.on("keyup", this.onKeyUp, this);
39459 if(this.forceSelection){
39460 this.on('blur', this.doForce, this);
39464 onDestroy : function(){
39466 this.view.setStore(null);
39467 this.view.el.removeAllListeners();
39468 this.view.el.remove();
39469 this.view.purgeListeners();
39472 this.list.destroy();
39475 this.store.un('beforeload', this.onBeforeLoad, this);
39476 this.store.un('load', this.onLoad, this);
39477 this.store.un('loadexception', this.onLoadException, this);
39479 Roo.form.ComboBox.superclass.onDestroy.call(this);
39483 fireKey : function(e){
39484 if(e.isNavKeyPress() && !this.list.isVisible()){
39485 this.fireEvent("specialkey", this, e);
39490 onResize: function(w, h){
39491 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39493 if(typeof w != 'number'){
39494 // we do not handle it!?!?
39497 var tw = this.trigger.getWidth();
39498 tw += this.addicon ? this.addicon.getWidth() : 0;
39499 tw += this.editicon ? this.editicon.getWidth() : 0;
39501 this.el.setWidth( this.adjustWidth('input', x));
39503 this.trigger.setStyle('left', x+'px');
39505 if(this.list && this.listWidth === undefined){
39506 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39507 this.list.setWidth(lw);
39508 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39516 * Allow or prevent the user from directly editing the field text. If false is passed,
39517 * the user will only be able to select from the items defined in the dropdown list. This method
39518 * is the runtime equivalent of setting the 'editable' config option at config time.
39519 * @param {Boolean} value True to allow the user to directly edit the field text
39521 setEditable : function(value){
39522 if(value == this.editable){
39525 this.editable = value;
39527 this.el.dom.setAttribute('readOnly', true);
39528 this.el.on('mousedown', this.onTriggerClick, this);
39529 this.el.addClass('x-combo-noedit');
39531 this.el.dom.setAttribute('readOnly', false);
39532 this.el.un('mousedown', this.onTriggerClick, this);
39533 this.el.removeClass('x-combo-noedit');
39538 onBeforeLoad : function(){
39539 if(!this.hasFocus){
39542 this.innerList.update(this.loadingText ?
39543 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39544 this.restrictHeight();
39545 this.selectedIndex = -1;
39549 onLoad : function(){
39550 if(!this.hasFocus){
39553 if(this.store.getCount() > 0){
39555 this.restrictHeight();
39556 if(this.lastQuery == this.allQuery){
39558 this.el.dom.select();
39560 if(!this.selectByValue(this.value, true)){
39561 this.select(0, true);
39565 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39566 this.taTask.delay(this.typeAheadDelay);
39570 this.onEmptyResults();
39575 onLoadException : function()
39578 Roo.log(this.store.reader.jsonData);
39579 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39580 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39586 onTypeAhead : function(){
39587 if(this.store.getCount() > 0){
39588 var r = this.store.getAt(0);
39589 var newValue = r.data[this.displayField];
39590 var len = newValue.length;
39591 var selStart = this.getRawValue().length;
39592 if(selStart != len){
39593 this.setRawValue(newValue);
39594 this.selectText(selStart, newValue.length);
39600 onSelect : function(record, index){
39601 if(this.fireEvent('beforeselect', this, record, index) !== false){
39602 this.setFromData(index > -1 ? record.data : false);
39604 this.fireEvent('select', this, record, index);
39609 * Returns the currently selected field value or empty string if no value is set.
39610 * @return {String} value The selected value
39612 getValue : function(){
39613 if(this.valueField){
39614 return typeof this.value != 'undefined' ? this.value : '';
39616 return Roo.form.ComboBox.superclass.getValue.call(this);
39621 * Clears any text/value currently set in the field
39623 clearValue : function(){
39624 if(this.hiddenField){
39625 this.hiddenField.value = '';
39628 this.setRawValue('');
39629 this.lastSelectionText = '';
39634 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39635 * will be displayed in the field. If the value does not match the data value of an existing item,
39636 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39637 * Otherwise the field will be blank (although the value will still be set).
39638 * @param {String} value The value to match
39640 setValue : function(v){
39642 if(this.valueField){
39643 var r = this.findRecord(this.valueField, v);
39645 text = r.data[this.displayField];
39646 }else if(this.valueNotFoundText !== undefined){
39647 text = this.valueNotFoundText;
39650 this.lastSelectionText = text;
39651 if(this.hiddenField){
39652 this.hiddenField.value = v;
39654 Roo.form.ComboBox.superclass.setValue.call(this, text);
39658 * @property {Object} the last set data for the element
39663 * Sets the value of the field based on a object which is related to the record format for the store.
39664 * @param {Object} value the value to set as. or false on reset?
39666 setFromData : function(o){
39667 var dv = ''; // display value
39668 var vv = ''; // value value..
39670 if (this.displayField) {
39671 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39673 // this is an error condition!!!
39674 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39677 if(this.valueField){
39678 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39680 if(this.hiddenField){
39681 this.hiddenField.value = vv;
39683 this.lastSelectionText = dv;
39684 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39688 // no hidden field.. - we store the value in 'value', but still display
39689 // display field!!!!
39690 this.lastSelectionText = dv;
39691 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39697 reset : function(){
39698 // overridden so that last data is reset..
39699 this.setValue(this.originalValue);
39700 this.clearInvalid();
39701 this.lastData = false;
39703 this.view.clearSelections();
39707 findRecord : function(prop, value){
39709 if(this.store.getCount() > 0){
39710 this.store.each(function(r){
39711 if(r.data[prop] == value){
39721 getName: function()
39723 // returns hidden if it's set..
39724 if (!this.rendered) {return ''};
39725 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39729 onViewMove : function(e, t){
39730 this.inKeyMode = false;
39734 onViewOver : function(e, t){
39735 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39738 var item = this.view.findItemFromChild(t);
39740 var index = this.view.indexOf(item);
39741 this.select(index, false);
39746 onViewClick : function(doFocus)
39748 var index = this.view.getSelectedIndexes()[0];
39749 var r = this.store.getAt(index);
39751 this.onSelect(r, index);
39753 if(doFocus !== false && !this.blockFocus){
39759 restrictHeight : function(){
39760 this.innerList.dom.style.height = '';
39761 var inner = this.innerList.dom;
39762 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39763 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39764 this.list.beginUpdate();
39765 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39766 this.list.alignTo(this.el, this.listAlign);
39767 this.list.endUpdate();
39771 onEmptyResults : function(){
39776 * Returns true if the dropdown list is expanded, else false.
39778 isExpanded : function(){
39779 return this.list.isVisible();
39783 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39784 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39785 * @param {String} value The data value of the item to select
39786 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39787 * selected item if it is not currently in view (defaults to true)
39788 * @return {Boolean} True if the value matched an item in the list, else false
39790 selectByValue : function(v, scrollIntoView){
39791 if(v !== undefined && v !== null){
39792 var r = this.findRecord(this.valueField || this.displayField, v);
39794 this.select(this.store.indexOf(r), scrollIntoView);
39802 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39803 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39804 * @param {Number} index The zero-based index of the list item to select
39805 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39806 * selected item if it is not currently in view (defaults to true)
39808 select : function(index, scrollIntoView){
39809 this.selectedIndex = index;
39810 this.view.select(index);
39811 if(scrollIntoView !== false){
39812 var el = this.view.getNode(index);
39814 this.innerList.scrollChildIntoView(el, false);
39820 selectNext : function(){
39821 var ct = this.store.getCount();
39823 if(this.selectedIndex == -1){
39825 }else if(this.selectedIndex < ct-1){
39826 this.select(this.selectedIndex+1);
39832 selectPrev : function(){
39833 var ct = this.store.getCount();
39835 if(this.selectedIndex == -1){
39837 }else if(this.selectedIndex != 0){
39838 this.select(this.selectedIndex-1);
39844 onKeyUp : function(e){
39845 if(this.editable !== false && !e.isSpecialKey()){
39846 this.lastKey = e.getKey();
39847 this.dqTask.delay(this.queryDelay);
39852 validateBlur : function(){
39853 return !this.list || !this.list.isVisible();
39857 initQuery : function(){
39858 this.doQuery(this.getRawValue());
39862 doForce : function(){
39863 if(this.el.dom.value.length > 0){
39864 this.el.dom.value =
39865 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39871 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39872 * query allowing the query action to be canceled if needed.
39873 * @param {String} query The SQL query to execute
39874 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39875 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39876 * saved in the current store (defaults to false)
39878 doQuery : function(q, forceAll){
39879 if(q === undefined || q === null){
39884 forceAll: forceAll,
39888 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39892 forceAll = qe.forceAll;
39893 if(forceAll === true || (q.length >= this.minChars)){
39894 if(this.lastQuery != q || this.alwaysQuery){
39895 this.lastQuery = q;
39896 if(this.mode == 'local'){
39897 this.selectedIndex = -1;
39899 this.store.clearFilter();
39901 this.store.filter(this.displayField, q);
39905 this.store.baseParams[this.queryParam] = q;
39907 params: this.getParams(q)
39912 this.selectedIndex = -1;
39919 getParams : function(q){
39921 //p[this.queryParam] = q;
39924 p.limit = this.pageSize;
39930 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
39932 collapse : function(){
39933 if(!this.isExpanded()){
39937 Roo.get(document).un('mousedown', this.collapseIf, this);
39938 Roo.get(document).un('mousewheel', this.collapseIf, this);
39939 if (!this.editable) {
39940 Roo.get(document).un('keydown', this.listKeyPress, this);
39942 this.fireEvent('collapse', this);
39946 collapseIf : function(e){
39947 if(!e.within(this.wrap) && !e.within(this.list)){
39953 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
39955 expand : function(){
39956 if(this.isExpanded() || !this.hasFocus){
39959 this.list.alignTo(this.el, this.listAlign);
39961 Roo.get(document).on('mousedown', this.collapseIf, this);
39962 Roo.get(document).on('mousewheel', this.collapseIf, this);
39963 if (!this.editable) {
39964 Roo.get(document).on('keydown', this.listKeyPress, this);
39967 this.fireEvent('expand', this);
39971 // Implements the default empty TriggerField.onTriggerClick function
39972 onTriggerClick : function(){
39976 if(this.isExpanded()){
39978 if (!this.blockFocus) {
39983 this.hasFocus = true;
39984 if(this.triggerAction == 'all') {
39985 this.doQuery(this.allQuery, true);
39987 this.doQuery(this.getRawValue());
39989 if (!this.blockFocus) {
39994 listKeyPress : function(e)
39996 //Roo.log('listkeypress');
39997 // scroll to first matching element based on key pres..
39998 if (e.isSpecialKey()) {
40001 var k = String.fromCharCode(e.getKey()).toUpperCase();
40004 var csel = this.view.getSelectedNodes();
40005 var cselitem = false;
40007 var ix = this.view.indexOf(csel[0]);
40008 cselitem = this.store.getAt(ix);
40009 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40015 this.store.each(function(v) {
40017 // start at existing selection.
40018 if (cselitem.id == v.id) {
40024 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40025 match = this.store.indexOf(v);
40030 if (match === false) {
40031 return true; // no more action?
40034 this.view.select(match);
40035 var sn = Roo.get(this.view.getSelectedNodes()[0])
40036 sn.scrollIntoView(sn.dom.parentNode, false);
40040 * @cfg {Boolean} grow
40044 * @cfg {Number} growMin
40048 * @cfg {Number} growMax
40056 * Copyright(c) 2010-2012, Roo J Solutions Limited
40063 * @class Roo.form.ComboBoxArray
40064 * @extends Roo.form.TextField
40065 * A facebook style adder... for lists of email / people / countries etc...
40066 * pick multiple items from a combo box, and shows each one.
40068 * Fred [x] Brian [x] [Pick another |v]
40071 * For this to work: it needs various extra information
40072 * - normal combo problay has
40074 * + displayField, valueField
40076 * For our purpose...
40079 * If we change from 'extends' to wrapping...
40086 * Create a new ComboBoxArray.
40087 * @param {Object} config Configuration options
40091 Roo.form.ComboBoxArray = function(config)
40094 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40096 this.items = new Roo.util.MixedCollection(false);
40098 // construct the child combo...
40108 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40111 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40116 // behavies liek a hiddne field
40117 inputType: 'hidden',
40119 * @cfg {Number} width The width of the box that displays the selected element
40126 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40130 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40132 hiddenName : false,
40135 // private the array of items that are displayed..
40137 // private - the hidden field el.
40139 // private - the filed el..
40142 //validateValue : function() { return true; }, // all values are ok!
40143 //onAddClick: function() { },
40145 onRender : function(ct, position)
40148 // create the standard hidden element
40149 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40152 // give fake names to child combo;
40153 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40154 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40156 this.combo = Roo.factory(this.combo, Roo.form);
40157 this.combo.onRender(ct, position);
40158 if (typeof(this.combo.width) != 'undefined') {
40159 this.combo.onResize(this.combo.width,0);
40162 this.combo.initEvents();
40164 // assigned so form know we need to do this..
40165 this.store = this.combo.store;
40166 this.valueField = this.combo.valueField;
40167 this.displayField = this.combo.displayField ;
40170 this.combo.wrap.addClass('x-cbarray-grp');
40172 var cbwrap = this.combo.wrap.createChild(
40173 {tag: 'div', cls: 'x-cbarray-cb'},
40178 this.hiddenEl = this.combo.wrap.createChild({
40179 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40181 this.el = this.combo.wrap.createChild({
40182 tag: 'input', type:'hidden' , name: this.name, value : ''
40184 // this.el.dom.removeAttribute("name");
40187 this.outerWrap = this.combo.wrap;
40188 this.wrap = cbwrap;
40190 this.outerWrap.setWidth(this.width);
40191 this.outerWrap.dom.removeChild(this.el.dom);
40193 this.wrap.dom.appendChild(this.el.dom);
40194 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40195 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40197 this.combo.trigger.setStyle('position','relative');
40198 this.combo.trigger.setStyle('left', '0px');
40199 this.combo.trigger.setStyle('top', '2px');
40201 this.combo.el.setStyle('vertical-align', 'text-bottom');
40203 //this.trigger.setStyle('vertical-align', 'top');
40205 // this should use the code from combo really... on('add' ....)
40209 this.adder = this.outerWrap.createChild(
40210 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40212 this.adder.on('click', function(e) {
40213 _t.fireEvent('adderclick', this, e);
40217 //this.adder.on('click', this.onAddClick, _t);
40220 this.combo.on('select', function(cb, rec, ix) {
40221 this.addItem(rec.data);
40224 cb.el.dom.value = '';
40225 //cb.lastData = rec.data;
40234 getName: function()
40236 // returns hidden if it's set..
40237 if (!this.rendered) {return ''};
40238 return this.hiddenName ? this.hiddenName : this.name;
40243 onResize: function(w, h){
40246 // not sure if this is needed..
40247 //this.combo.onResize(w,h);
40249 if(typeof w != 'number'){
40250 // we do not handle it!?!?
40253 var tw = this.combo.trigger.getWidth();
40254 tw += this.addicon ? this.addicon.getWidth() : 0;
40255 tw += this.editicon ? this.editicon.getWidth() : 0;
40257 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40259 this.combo.trigger.setStyle('left', '0px');
40261 if(this.list && this.listWidth === undefined){
40262 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40263 this.list.setWidth(lw);
40264 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40271 addItem: function(rec)
40273 var valueField = this.combo.valueField;
40274 var displayField = this.combo.displayField;
40275 if (this.items.indexOfKey(rec[valueField]) > -1) {
40276 //console.log("GOT " + rec.data.id);
40280 var x = new Roo.form.ComboBoxArray.Item({
40281 //id : rec[this.idField],
40283 displayField : displayField ,
40284 tipField : displayField ,
40288 this.items.add(rec[valueField],x);
40289 // add it before the element..
40290 this.updateHiddenEl();
40291 x.render(this.outerWrap, this.wrap.dom);
40292 // add the image handler..
40295 updateHiddenEl : function()
40298 if (!this.hiddenEl) {
40302 var idField = this.combo.valueField;
40304 this.items.each(function(f) {
40305 ar.push(f.data[idField]);
40308 this.hiddenEl.dom.value = ar.join(',');
40314 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40315 this.items.each(function(f) {
40318 this.el.dom.value = '';
40319 if (this.hiddenEl) {
40320 this.hiddenEl.dom.value = '';
40324 getValue: function()
40326 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40328 setValue: function(v) // not a valid action - must use addItems..
40335 if (this.store.isLocal && (typeof(v) == 'string')) {
40336 // then we can use the store to find the values..
40337 // comma seperated at present.. this needs to allow JSON based encoding..
40338 this.hiddenEl.value = v;
40340 Roo.each(v.split(','), function(k) {
40341 Roo.log("CHECK " + this.valueField + ',' + k);
40342 var li = this.store.query(this.valueField, k);
40347 add[this.valueField] = k;
40348 add[this.displayField] = li.item(0).data[this.displayField];
40354 if (typeof(v) == 'object') {
40355 // then let's assume it's an array of objects..
40356 Roo.each(v, function(l) {
40364 setFromData: function(v)
40366 // this recieves an object, if setValues is called.
40368 this.el.dom.value = v[this.displayField];
40369 this.hiddenEl.dom.value = v[this.valueField];
40370 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40373 var kv = v[this.valueField];
40374 var dv = v[this.displayField];
40375 kv = typeof(kv) != 'string' ? '' : kv;
40376 dv = typeof(dv) != 'string' ? '' : dv;
40379 var keys = kv.split(',');
40380 var display = dv.split(',');
40381 for (var i = 0 ; i < keys.length; i++) {
40384 add[this.valueField] = keys[i];
40385 add[this.displayField] = display[i];
40393 * Validates the combox array value
40394 * @return {Boolean} True if the value is valid, else false
40396 validate : function(){
40397 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40398 this.clearInvalid();
40404 validateValue : function(value){
40405 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40410 * Mark this combo array as invalid
40411 * @param {String} msg The validation message
40413 markInvalid : function(msg){
40414 if(!this.rendered || this.preventMark){ // not rendered
40417 this.combo.el.addClass(this.invalidClass);
40418 msg = msg || this.invalidText;
40419 switch(this.msgTarget){
40421 this.el.dom.qtip = msg;
40422 this.el.dom.qclass = 'x-form-invalid-tip';
40423 if(Roo.QuickTips){ // fix for floating editors interacting with DND
40424 Roo.QuickTips.enable();
40428 this.el.dom.title = msg;
40432 var elp = this.el.findParent('.x-form-element', 5, true);
40433 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
40434 this.errorEl.setWidth(elp.getWidth(true)-20);
40436 this.errorEl.update(msg);
40437 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
40440 if(!this.errorIcon){
40441 var elp = this.el.findParent('.x-form-element', 5, true);
40442 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
40444 this.alignErrorIcon();
40445 this.errorIcon.dom.qtip = msg;
40446 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
40447 this.errorIcon.show();
40448 this.on('resize', this.alignErrorIcon, this);
40451 var t = Roo.getDom(this.msgTarget);
40453 t.style.display = this.msgDisplay;
40456 this.fireEvent('invalid', this, msg);
40464 * @class Roo.form.ComboBoxArray.Item
40465 * @extends Roo.BoxComponent
40466 * A selected item in the list
40467 * Fred [x] Brian [x] [Pick another |v]
40470 * Create a new item.
40471 * @param {Object} config Configuration options
40474 Roo.form.ComboBoxArray.Item = function(config) {
40475 config.id = Roo.id();
40476 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40479 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40482 displayField : false,
40486 defaultAutoCreate : {
40488 cls: 'x-cbarray-item',
40495 src : Roo.BLANK_IMAGE_URL ,
40503 onRender : function(ct, position)
40505 Roo.form.Field.superclass.onRender.call(this, ct, position);
40508 var cfg = this.getAutoCreate();
40509 this.el = ct.createChild(cfg, position);
40512 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40514 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40515 this.cb.renderer(this.data) :
40516 String.format('{0}',this.data[this.displayField]);
40519 this.el.child('div').dom.setAttribute('qtip',
40520 String.format('{0}',this.data[this.tipField])
40523 this.el.child('img').on('click', this.remove, this);
40527 remove : function()
40530 this.cb.items.remove(this);
40531 this.el.child('img').un('click', this.remove, this);
40533 this.cb.updateHiddenEl();
40538 * Ext JS Library 1.1.1
40539 * Copyright(c) 2006-2007, Ext JS, LLC.
40541 * Originally Released Under LGPL - original licence link has changed is not relivant.
40544 * <script type="text/javascript">
40547 * @class Roo.form.Checkbox
40548 * @extends Roo.form.Field
40549 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40551 * Creates a new Checkbox
40552 * @param {Object} config Configuration options
40554 Roo.form.Checkbox = function(config){
40555 Roo.form.Checkbox.superclass.constructor.call(this, config);
40559 * Fires when the checkbox is checked or unchecked.
40560 * @param {Roo.form.Checkbox} this This checkbox
40561 * @param {Boolean} checked The new checked value
40567 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40569 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40571 focusClass : undefined,
40573 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40575 fieldClass: "x-form-field",
40577 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40581 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40582 * {tag: "input", type: "checkbox", autocomplete: "off"})
40584 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40586 * @cfg {String} boxLabel The text that appears beside the checkbox
40590 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40594 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40596 valueOff: '0', // value when not checked..
40598 actionMode : 'viewEl',
40601 itemCls : 'x-menu-check-item x-form-item',
40602 groupClass : 'x-menu-group-item',
40603 inputType : 'hidden',
40606 inSetChecked: false, // check that we are not calling self...
40608 inputElement: false, // real input element?
40609 basedOn: false, // ????
40611 isFormField: true, // not sure where this is needed!!!!
40613 onResize : function(){
40614 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40615 if(!this.boxLabel){
40616 this.el.alignTo(this.wrap, 'c-c');
40620 initEvents : function(){
40621 Roo.form.Checkbox.superclass.initEvents.call(this);
40622 this.el.on("click", this.onClick, this);
40623 this.el.on("change", this.onClick, this);
40627 getResizeEl : function(){
40631 getPositionEl : function(){
40636 onRender : function(ct, position){
40637 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40639 if(this.inputValue !== undefined){
40640 this.el.dom.value = this.inputValue;
40643 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40644 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40645 var viewEl = this.wrap.createChild({
40646 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40647 this.viewEl = viewEl;
40648 this.wrap.on('click', this.onClick, this);
40650 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40651 this.el.on('propertychange', this.setFromHidden, this); //ie
40656 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40657 // viewEl.on('click', this.onClick, this);
40659 //if(this.checked){
40660 this.setChecked(this.checked);
40662 //this.checked = this.el.dom;
40668 initValue : Roo.emptyFn,
40671 * Returns the checked state of the checkbox.
40672 * @return {Boolean} True if checked, else false
40674 getValue : function(){
40676 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40678 return this.valueOff;
40683 onClick : function(){
40684 this.setChecked(!this.checked);
40686 //if(this.el.dom.checked != this.checked){
40687 // this.setValue(this.el.dom.checked);
40692 * Sets the checked state of the checkbox.
40693 * On is always based on a string comparison between inputValue and the param.
40694 * @param {Boolean/String} value - the value to set
40695 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40697 setValue : function(v,suppressEvent){
40700 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40701 //if(this.el && this.el.dom){
40702 // this.el.dom.checked = this.checked;
40703 // this.el.dom.defaultChecked = this.checked;
40705 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40706 //this.fireEvent("check", this, this.checked);
40709 setChecked : function(state,suppressEvent)
40711 if (this.inSetChecked) {
40712 this.checked = state;
40718 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40720 this.checked = state;
40721 if(suppressEvent !== true){
40722 this.fireEvent('check', this, state);
40724 this.inSetChecked = true;
40725 this.el.dom.value = state ? this.inputValue : this.valueOff;
40726 this.inSetChecked = false;
40729 // handle setting of hidden value by some other method!!?!?
40730 setFromHidden: function()
40735 //console.log("SET FROM HIDDEN");
40736 //alert('setFrom hidden');
40737 this.setValue(this.el.dom.value);
40740 onDestroy : function()
40743 Roo.get(this.viewEl).remove();
40746 Roo.form.Checkbox.superclass.onDestroy.call(this);
40751 * Ext JS Library 1.1.1
40752 * Copyright(c) 2006-2007, Ext JS, LLC.
40754 * Originally Released Under LGPL - original licence link has changed is not relivant.
40757 * <script type="text/javascript">
40761 * @class Roo.form.Radio
40762 * @extends Roo.form.Checkbox
40763 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40764 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40766 * Creates a new Radio
40767 * @param {Object} config Configuration options
40769 Roo.form.Radio = function(){
40770 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40772 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40773 inputType: 'radio',
40776 * If this radio is part of a group, it will return the selected value
40779 getGroupValue : function(){
40780 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40784 onRender : function(ct, position){
40785 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40787 if(this.inputValue !== undefined){
40788 this.el.dom.value = this.inputValue;
40791 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40792 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40793 //var viewEl = this.wrap.createChild({
40794 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40795 //this.viewEl = viewEl;
40796 //this.wrap.on('click', this.onClick, this);
40798 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40799 //this.el.on('propertychange', this.setFromHidden, this); //ie
40804 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40805 // viewEl.on('click', this.onClick, this);
40808 this.el.dom.checked = 'checked' ;
40814 });//<script type="text/javascript">
40817 * Ext JS Library 1.1.1
40818 * Copyright(c) 2006-2007, Ext JS, LLC.
40819 * licensing@extjs.com
40821 * http://www.extjs.com/license
40827 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
40828 * - IE ? - no idea how much works there.
40836 * @class Ext.form.HtmlEditor
40837 * @extends Ext.form.Field
40838 * Provides a lightweight HTML Editor component.
40840 * This has been tested on Fireforx / Chrome.. IE may not be so great..
40842 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
40843 * supported by this editor.</b><br/><br/>
40844 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
40845 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40847 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
40849 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
40853 * @cfg {String} createLinkText The default text for the create link prompt
40855 createLinkText : 'Please enter the URL for the link:',
40857 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
40859 defaultLinkValue : 'http:/'+'/',
40862 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40867 * @cfg {Number} height (in pixels)
40871 * @cfg {Number} width (in pixels)
40876 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
40879 stylesheets: false,
40884 // private properties
40885 validationEvent : false,
40887 initialized : false,
40889 sourceEditMode : false,
40890 onFocus : Roo.emptyFn,
40892 hideMode:'offsets',
40894 defaultAutoCreate : { // modified by initCompnoent..
40896 style:"width:500px;height:300px;",
40897 autocomplete: "off"
40901 initComponent : function(){
40904 * @event initialize
40905 * Fires when the editor is fully initialized (including the iframe)
40906 * @param {HtmlEditor} this
40911 * Fires when the editor is first receives the focus. Any insertion must wait
40912 * until after this event.
40913 * @param {HtmlEditor} this
40917 * @event beforesync
40918 * Fires before the textarea is updated with content from the editor iframe. Return false
40919 * to cancel the sync.
40920 * @param {HtmlEditor} this
40921 * @param {String} html
40925 * @event beforepush
40926 * Fires before the iframe editor is updated with content from the textarea. Return false
40927 * to cancel the push.
40928 * @param {HtmlEditor} this
40929 * @param {String} html
40934 * Fires when the textarea is updated with content from the editor iframe.
40935 * @param {HtmlEditor} this
40936 * @param {String} html
40941 * Fires when the iframe editor is updated with content from the textarea.
40942 * @param {HtmlEditor} this
40943 * @param {String} html
40947 * @event editmodechange
40948 * Fires when the editor switches edit modes
40949 * @param {HtmlEditor} this
40950 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
40952 editmodechange: true,
40954 * @event editorevent
40955 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40956 * @param {HtmlEditor} this
40960 this.defaultAutoCreate = {
40962 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
40963 autocomplete: "off"
40968 * Protected method that will not generally be called directly. It
40969 * is called when the editor creates its toolbar. Override this method if you need to
40970 * add custom toolbar buttons.
40971 * @param {HtmlEditor} editor
40973 createToolbar : function(editor){
40974 if (!editor.toolbars || !editor.toolbars.length) {
40975 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
40978 for (var i =0 ; i < editor.toolbars.length;i++) {
40979 editor.toolbars[i] = Roo.factory(
40980 typeof(editor.toolbars[i]) == 'string' ?
40981 { xtype: editor.toolbars[i]} : editor.toolbars[i],
40982 Roo.form.HtmlEditor);
40983 editor.toolbars[i].init(editor);
40990 * Protected method that will not generally be called directly. It
40991 * is called when the editor initializes the iframe with HTML contents. Override this method if you
40992 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
40994 getDocMarkup : function(){
40997 if (this.stylesheets === false) {
40999 Roo.get(document.head).select('style').each(function(node) {
41000 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41003 Roo.get(document.head).select('link').each(function(node) {
41004 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41007 } else if (!this.stylesheets.length) {
41009 st = '<style type="text/css">' +
41010 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41013 Roo.each(this.stylesheets, function(s) {
41014 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
41019 st += '<style type="text/css">' +
41020 'IMG { cursor: pointer } ' +
41024 return '<html><head>' + st +
41025 //<style type="text/css">' +
41026 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41028 ' </head><body class="roo-htmleditor-body"></body></html>';
41032 onRender : function(ct, position)
41035 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
41036 this.el.dom.style.border = '0 none';
41037 this.el.dom.setAttribute('tabIndex', -1);
41038 this.el.addClass('x-hidden');
41039 if(Roo.isIE){ // fix IE 1px bogus margin
41040 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41042 this.wrap = this.el.wrap({
41043 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
41046 if (this.resizable) {
41047 this.resizeEl = new Roo.Resizable(this.wrap, {
41051 minHeight : this.height,
41052 height: this.height,
41053 handles : this.resizable,
41056 resize : function(r, w, h) {
41057 _t.onResize(w,h); // -something
41064 this.frameId = Roo.id();
41066 this.createToolbar(this);
41070 var iframe = this.wrap.createChild({
41073 name: this.frameId,
41074 frameBorder : 'no',
41075 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41079 // console.log(iframe);
41080 //this.wrap.dom.appendChild(iframe);
41082 this.iframe = iframe.dom;
41084 this.assignDocWin();
41086 this.doc.designMode = 'on';
41089 this.doc.write(this.getDocMarkup());
41093 var task = { // must defer to wait for browser to be ready
41095 //console.log("run task?" + this.doc.readyState);
41096 this.assignDocWin();
41097 if(this.doc.body || this.doc.readyState == 'complete'){
41099 this.doc.designMode="on";
41103 Roo.TaskMgr.stop(task);
41104 this.initEditor.defer(10, this);
41111 Roo.TaskMgr.start(task);
41114 this.setSize(this.wrap.getSize());
41116 if (this.resizeEl) {
41117 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
41118 // should trigger onReize..
41123 onResize : function(w, h)
41125 //Roo.log('resize: ' +w + ',' + h );
41126 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
41127 if(this.el && this.iframe){
41128 if(typeof w == 'number'){
41129 var aw = w - this.wrap.getFrameWidth('lr');
41130 this.el.setWidth(this.adjustWidth('textarea', aw));
41131 this.iframe.style.width = aw + 'px';
41133 if(typeof h == 'number'){
41135 for (var i =0; i < this.toolbars.length;i++) {
41136 // fixme - ask toolbars for heights?
41137 tbh += this.toolbars[i].tb.el.getHeight();
41138 if (this.toolbars[i].footer) {
41139 tbh += this.toolbars[i].footer.el.getHeight();
41146 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
41147 ah -= 5; // knock a few pixes off for look..
41148 this.el.setHeight(this.adjustWidth('textarea', ah));
41149 this.iframe.style.height = ah + 'px';
41151 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
41158 * Toggles the editor between standard and source edit mode.
41159 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41161 toggleSourceEdit : function(sourceEditMode){
41163 this.sourceEditMode = sourceEditMode === true;
41165 if(this.sourceEditMode){
41167 // Roo.log(this.syncValue());
41169 this.iframe.className = 'x-hidden';
41170 this.el.removeClass('x-hidden');
41171 this.el.dom.removeAttribute('tabIndex');
41175 // Roo.log(this.pushValue());
41177 this.iframe.className = '';
41178 this.el.addClass('x-hidden');
41179 this.el.dom.setAttribute('tabIndex', -1);
41182 this.setSize(this.wrap.getSize());
41183 this.fireEvent('editmodechange', this, this.sourceEditMode);
41186 // private used internally
41187 createLink : function(){
41188 var url = prompt(this.createLinkText, this.defaultLinkValue);
41189 if(url && url != 'http:/'+'/'){
41190 this.relayCmd('createlink', url);
41194 // private (for BoxComponent)
41195 adjustSize : Roo.BoxComponent.prototype.adjustSize,
41197 // private (for BoxComponent)
41198 getResizeEl : function(){
41202 // private (for BoxComponent)
41203 getPositionEl : function(){
41208 initEvents : function(){
41209 this.originalValue = this.getValue();
41213 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
41216 markInvalid : Roo.emptyFn,
41218 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
41221 clearInvalid : Roo.emptyFn,
41223 setValue : function(v){
41224 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
41229 * Protected method that will not generally be called directly. If you need/want
41230 * custom HTML cleanup, this is the method you should override.
41231 * @param {String} html The HTML to be cleaned
41232 * return {String} The cleaned HTML
41234 cleanHtml : function(html){
41235 html = String(html);
41236 if(html.length > 5){
41237 if(Roo.isSafari){ // strip safari nonsense
41238 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41241 if(html == ' '){
41248 * Protected method that will not generally be called directly. Syncs the contents
41249 * of the editor iframe with the textarea.
41251 syncValue : function(){
41252 if(this.initialized){
41253 var bd = (this.doc.body || this.doc.documentElement);
41254 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41255 var html = bd.innerHTML;
41257 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41258 var m = bs.match(/text-align:(.*?);/i);
41260 html = '<div style="'+m[0]+'">' + html + '</div>';
41263 html = this.cleanHtml(html);
41264 // fix up the special chars.. normaly like back quotes in word...
41265 // however we do not want to do this with chinese..
41266 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41267 var cc = b.charCodeAt();
41269 (cc >= 0x4E00 && cc < 0xA000 ) ||
41270 (cc >= 0x3400 && cc < 0x4E00 ) ||
41271 (cc >= 0xf900 && cc < 0xfb00 )
41277 if(this.fireEvent('beforesync', this, html) !== false){
41278 this.el.dom.value = html;
41279 this.fireEvent('sync', this, html);
41285 * Protected method that will not generally be called directly. Pushes the value of the textarea
41286 * into the iframe editor.
41288 pushValue : function(){
41289 if(this.initialized){
41290 var v = this.el.dom.value;
41296 if(this.fireEvent('beforepush', this, v) !== false){
41297 var d = (this.doc.body || this.doc.documentElement);
41299 this.cleanUpPaste();
41300 this.el.dom.value = d.innerHTML;
41301 this.fireEvent('push', this, v);
41307 deferFocus : function(){
41308 this.focus.defer(10, this);
41312 focus : function(){
41313 if(this.win && !this.sourceEditMode){
41320 assignDocWin: function()
41322 var iframe = this.iframe;
41325 this.doc = iframe.contentWindow.document;
41326 this.win = iframe.contentWindow;
41328 if (!Roo.get(this.frameId)) {
41331 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41332 this.win = Roo.get(this.frameId).dom.contentWindow;
41337 initEditor : function(){
41338 //console.log("INIT EDITOR");
41339 this.assignDocWin();
41343 this.doc.designMode="on";
41345 this.doc.write(this.getDocMarkup());
41348 var dbody = (this.doc.body || this.doc.documentElement);
41349 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41350 // this copies styles from the containing element into thsi one..
41351 // not sure why we need all of this..
41352 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41353 ss['background-attachment'] = 'fixed'; // w3c
41354 dbody.bgProperties = 'fixed'; // ie
41355 Roo.DomHelper.applyStyles(dbody, ss);
41356 Roo.EventManager.on(this.doc, {
41357 //'mousedown': this.onEditorEvent,
41358 'mouseup': this.onEditorEvent,
41359 'dblclick': this.onEditorEvent,
41360 'click': this.onEditorEvent,
41361 'keyup': this.onEditorEvent,
41366 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41368 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41369 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41371 this.initialized = true;
41373 this.fireEvent('initialize', this);
41378 onDestroy : function(){
41384 for (var i =0; i < this.toolbars.length;i++) {
41385 // fixme - ask toolbars for heights?
41386 this.toolbars[i].onDestroy();
41389 this.wrap.dom.innerHTML = '';
41390 this.wrap.remove();
41395 onFirstFocus : function(){
41397 this.assignDocWin();
41400 this.activated = true;
41401 for (var i =0; i < this.toolbars.length;i++) {
41402 this.toolbars[i].onFirstFocus();
41405 if(Roo.isGecko){ // prevent silly gecko errors
41407 var s = this.win.getSelection();
41408 if(!s.focusNode || s.focusNode.nodeType != 3){
41409 var r = s.getRangeAt(0);
41410 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41415 this.execCmd('useCSS', true);
41416 this.execCmd('styleWithCSS', false);
41419 this.fireEvent('activate', this);
41423 adjustFont: function(btn){
41424 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41425 //if(Roo.isSafari){ // safari
41428 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41429 if(Roo.isSafari){ // safari
41430 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41431 v = (v < 10) ? 10 : v;
41432 v = (v > 48) ? 48 : v;
41433 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41438 v = Math.max(1, v+adjust);
41440 this.execCmd('FontSize', v );
41443 onEditorEvent : function(e){
41444 this.fireEvent('editorevent', this, e);
41445 // this.updateToolbar();
41446 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41449 insertTag : function(tg)
41451 // could be a bit smarter... -> wrap the current selected tRoo..
41452 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41454 range = this.createRange(this.getSelection());
41455 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41456 wrappingNode.appendChild(range.extractContents());
41457 range.insertNode(wrappingNode);
41464 this.execCmd("formatblock", tg);
41468 insertText : function(txt)
41472 var range = this.createRange();
41473 range.deleteContents();
41474 //alert(Sender.getAttribute('label'));
41476 range.insertNode(this.doc.createTextNode(txt));
41480 relayBtnCmd : function(btn){
41481 this.relayCmd(btn.cmd);
41485 * Executes a Midas editor command on the editor document and performs necessary focus and
41486 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41487 * @param {String} cmd The Midas command
41488 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41490 relayCmd : function(cmd, value){
41492 this.execCmd(cmd, value);
41493 this.fireEvent('editorevent', this);
41494 //this.updateToolbar();
41499 * Executes a Midas editor command directly on the editor document.
41500 * For visual commands, you should use {@link #relayCmd} instead.
41501 * <b>This should only be called after the editor is initialized.</b>
41502 * @param {String} cmd The Midas command
41503 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41505 execCmd : function(cmd, value){
41506 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41513 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41515 * @param {String} text | dom node..
41517 insertAtCursor : function(text)
41522 if(!this.activated){
41528 var r = this.doc.selection.createRange();
41539 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41543 // from jquery ui (MIT licenced)
41545 var win = this.win;
41547 if (win.getSelection && win.getSelection().getRangeAt) {
41548 range = win.getSelection().getRangeAt(0);
41549 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41550 range.insertNode(node);
41551 } else if (win.document.selection && win.document.selection.createRange) {
41552 // no firefox support
41553 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41554 win.document.selection.createRange().pasteHTML(txt);
41556 // no firefox support
41557 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41558 this.execCmd('InsertHTML', txt);
41567 mozKeyPress : function(e){
41569 var c = e.getCharCode(), cmd;
41572 c = String.fromCharCode(c).toLowerCase();
41586 this.cleanUpPaste.defer(100, this);
41594 e.preventDefault();
41602 fixKeys : function(){ // load time branching for fastest keydown performance
41604 return function(e){
41605 var k = e.getKey(), r;
41608 r = this.doc.selection.createRange();
41611 r.pasteHTML('    ');
41618 r = this.doc.selection.createRange();
41620 var target = r.parentElement();
41621 if(!target || target.tagName.toLowerCase() != 'li'){
41623 r.pasteHTML('<br />');
41629 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41630 this.cleanUpPaste.defer(100, this);
41636 }else if(Roo.isOpera){
41637 return function(e){
41638 var k = e.getKey();
41642 this.execCmd('InsertHTML','    ');
41645 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41646 this.cleanUpPaste.defer(100, this);
41651 }else if(Roo.isSafari){
41652 return function(e){
41653 var k = e.getKey();
41657 this.execCmd('InsertText','\t');
41661 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41662 this.cleanUpPaste.defer(100, this);
41670 getAllAncestors: function()
41672 var p = this.getSelectedNode();
41675 a.push(p); // push blank onto stack..
41676 p = this.getParentElement();
41680 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41684 a.push(this.doc.body);
41688 lastSelNode : false,
41691 getSelection : function()
41693 this.assignDocWin();
41694 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41697 getSelectedNode: function()
41699 // this may only work on Gecko!!!
41701 // should we cache this!!!!
41706 var range = this.createRange(this.getSelection()).cloneRange();
41709 var parent = range.parentElement();
41711 var testRange = range.duplicate();
41712 testRange.moveToElementText(parent);
41713 if (testRange.inRange(range)) {
41716 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41719 parent = parent.parentElement;
41724 // is ancestor a text element.
41725 var ac = range.commonAncestorContainer;
41726 if (ac.nodeType == 3) {
41727 ac = ac.parentNode;
41730 var ar = ac.childNodes;
41733 var other_nodes = [];
41734 var has_other_nodes = false;
41735 for (var i=0;i<ar.length;i++) {
41736 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41739 // fullly contained node.
41741 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41746 // probably selected..
41747 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41748 other_nodes.push(ar[i]);
41752 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41757 has_other_nodes = true;
41759 if (!nodes.length && other_nodes.length) {
41760 nodes= other_nodes;
41762 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41768 createRange: function(sel)
41770 // this has strange effects when using with
41771 // top toolbar - not sure if it's a great idea.
41772 //this.editor.contentWindow.focus();
41773 if (typeof sel != "undefined") {
41775 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41777 return this.doc.createRange();
41780 return this.doc.createRange();
41783 getParentElement: function()
41786 this.assignDocWin();
41787 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41789 var range = this.createRange(sel);
41792 var p = range.commonAncestorContainer;
41793 while (p.nodeType == 3) { // text node
41804 * Range intersection.. the hard stuff...
41808 * [ -- selected range --- ]
41812 * if end is before start or hits it. fail.
41813 * if start is after end or hits it fail.
41815 * if either hits (but other is outside. - then it's not
41821 // @see http://www.thismuchiknow.co.uk/?p=64.
41822 rangeIntersectsNode : function(range, node)
41824 var nodeRange = node.ownerDocument.createRange();
41826 nodeRange.selectNode(node);
41828 nodeRange.selectNodeContents(node);
41831 var rangeStartRange = range.cloneRange();
41832 rangeStartRange.collapse(true);
41834 var rangeEndRange = range.cloneRange();
41835 rangeEndRange.collapse(false);
41837 var nodeStartRange = nodeRange.cloneRange();
41838 nodeStartRange.collapse(true);
41840 var nodeEndRange = nodeRange.cloneRange();
41841 nodeEndRange.collapse(false);
41843 return rangeStartRange.compareBoundaryPoints(
41844 Range.START_TO_START, nodeEndRange) == -1 &&
41845 rangeEndRange.compareBoundaryPoints(
41846 Range.START_TO_START, nodeStartRange) == 1;
41850 rangeCompareNode : function(range, node)
41852 var nodeRange = node.ownerDocument.createRange();
41854 nodeRange.selectNode(node);
41856 nodeRange.selectNodeContents(node);
41860 range.collapse(true);
41862 nodeRange.collapse(true);
41864 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41865 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41867 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41869 var nodeIsBefore = ss == 1;
41870 var nodeIsAfter = ee == -1;
41872 if (nodeIsBefore && nodeIsAfter)
41874 if (!nodeIsBefore && nodeIsAfter)
41875 return 1; //right trailed.
41877 if (nodeIsBefore && !nodeIsAfter)
41878 return 2; // left trailed.
41883 // private? - in a new class?
41884 cleanUpPaste : function()
41886 // cleans up the whole document..
41887 Roo.log('cleanuppaste');
41888 this.cleanUpChildren(this.doc.body);
41889 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41890 if (clean != this.doc.body.innerHTML) {
41891 this.doc.body.innerHTML = clean;
41896 cleanWordChars : function(input) {// change the chars to hex code
41897 var he = Roo.form.HtmlEditor;
41899 var output = input;
41900 Roo.each(he.swapCodes, function(sw) {
41901 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41903 output = output.replace(swapper, sw[1]);
41910 cleanUpChildren : function (n)
41912 if (!n.childNodes.length) {
41915 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41916 this.cleanUpChild(n.childNodes[i]);
41923 cleanUpChild : function (node)
41926 //console.log(node);
41927 if (node.nodeName == "#text") {
41928 // clean up silly Windows -- stuff?
41931 if (node.nodeName == "#comment") {
41932 node.parentNode.removeChild(node);
41933 // clean up silly Windows -- stuff?
41937 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
41939 node.parentNode.removeChild(node);
41944 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
41946 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41947 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41949 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41950 // remove_keep_children = true;
41953 if (remove_keep_children) {
41954 this.cleanUpChildren(node);
41955 // inserts everything just before this node...
41956 while (node.childNodes.length) {
41957 var cn = node.childNodes[0];
41958 node.removeChild(cn);
41959 node.parentNode.insertBefore(cn, node);
41961 node.parentNode.removeChild(node);
41965 if (!node.attributes || !node.attributes.length) {
41966 this.cleanUpChildren(node);
41970 function cleanAttr(n,v)
41973 if (v.match(/^\./) || v.match(/^\//)) {
41976 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41979 if (v.match(/^#/)) {
41982 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41983 node.removeAttribute(n);
41987 function cleanStyle(n,v)
41989 if (v.match(/expression/)) { //XSS?? should we even bother..
41990 node.removeAttribute(n);
41993 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.form.HtmlEditor.cwhite : ed.cwhite;
41994 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.form.HtmlEditor.cblack : ed.cblack;
41997 var parts = v.split(/;/);
42000 Roo.each(parts, function(p) {
42001 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42005 var l = p.split(':').shift().replace(/\s+/g,'');
42006 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42009 if ( cblack.indexOf(l) > -1) {
42010 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42011 //node.removeAttribute(n);
42015 // only allow 'c whitelisted system attributes'
42016 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42017 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42018 //node.removeAttribute(n);
42028 if (clean.length) {
42029 node.setAttribute(n, clean.join(';'));
42031 node.removeAttribute(n);
42037 for (var i = node.attributes.length-1; i > -1 ; i--) {
42038 var a = node.attributes[i];
42041 if (a.name.toLowerCase().substr(0,2)=='on') {
42042 node.removeAttribute(a.name);
42045 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
42046 node.removeAttribute(a.name);
42049 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
42050 cleanAttr(a.name,a.value); // fixme..
42053 if (a.name == 'style') {
42054 cleanStyle(a.name,a.value);
42057 /// clean up MS crap..
42058 // tecnically this should be a list of valid class'es..
42061 if (a.name == 'class') {
42062 if (a.value.match(/^Mso/)) {
42063 node.className = '';
42066 if (a.value.match(/body/)) {
42067 node.className = '';
42078 this.cleanUpChildren(node);
42084 // hide stuff that is not compatible
42098 * @event specialkey
42102 * @cfg {String} fieldClass @hide
42105 * @cfg {String} focusClass @hide
42108 * @cfg {String} autoCreate @hide
42111 * @cfg {String} inputType @hide
42114 * @cfg {String} invalidClass @hide
42117 * @cfg {String} invalidText @hide
42120 * @cfg {String} msgFx @hide
42123 * @cfg {String} validateOnBlur @hide
42127 Roo.form.HtmlEditor.white = [
42128 'area', 'br', 'img', 'input', 'hr', 'wbr',
42130 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42131 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42132 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42133 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42134 'table', 'ul', 'xmp',
42136 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42139 'dir', 'menu', 'ol', 'ul', 'dl',
42145 Roo.form.HtmlEditor.black = [
42146 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42148 'base', 'basefont', 'bgsound', 'blink', 'body',
42149 'frame', 'frameset', 'head', 'html', 'ilayer',
42150 'iframe', 'layer', 'link', 'meta', 'object',
42151 'script', 'style' ,'title', 'xml' // clean later..
42153 Roo.form.HtmlEditor.clean = [
42154 'script', 'style', 'title', 'xml'
42156 Roo.form.HtmlEditor.remove = [
42161 Roo.form.HtmlEditor.ablack = [
42165 Roo.form.HtmlEditor.aclean = [
42166 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42170 Roo.form.HtmlEditor.pwhite= [
42171 'http', 'https', 'mailto'
42174 // white listed style attributes.
42175 Roo.form.HtmlEditor.cwhite= [
42176 // 'text-align', /// default is to allow most things..
42182 // black listed style attributes.
42183 Roo.form.HtmlEditor.cblack= [
42184 // 'font-size' -- this can be set by the project
42188 Roo.form.HtmlEditor.swapCodes =[
42199 // <script type="text/javascript">
42202 * Ext JS Library 1.1.1
42203 * Copyright(c) 2006-2007, Ext JS, LLC.
42209 * @class Roo.form.HtmlEditorToolbar1
42214 new Roo.form.HtmlEditor({
42217 new Roo.form.HtmlEditorToolbar1({
42218 disable : { fonts: 1 , format: 1, ..., ... , ...],
42224 * @cfg {Object} disable List of elements to disable..
42225 * @cfg {Array} btns List of additional buttons.
42229 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
42232 Roo.form.HtmlEditor.ToolbarStandard = function(config)
42235 Roo.apply(this, config);
42237 // default disabled, based on 'good practice'..
42238 this.disable = this.disable || {};
42239 Roo.applyIf(this.disable, {
42242 specialElements : true
42246 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42247 // dont call parent... till later.
42250 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
42258 * @cfg {Object} disable List of toolbar elements to disable
42263 * @cfg {Array} fontFamilies An array of available font families
42281 // "á" , ?? a acute?
42286 "°" // , // degrees
42288 // "é" , // e ecute
42289 // "ú" , // u ecute?
42292 specialElements : [
42294 text: "Insert Table",
42297 ihtml : '<table><tr><td>Cell</td></tr></table>'
42301 text: "Insert Image",
42304 ihtml : '<img src="about:blank"/>'
42313 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
42314 "input:submit", "input:button", "select", "textarea", "label" ],
42317 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
42319 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
42327 * @cfg {String} defaultFont default font to use.
42329 defaultFont: 'tahoma',
42331 fontSelect : false,
42334 formatCombo : false,
42336 init : function(editor)
42338 this.editor = editor;
42341 var fid = editor.frameId;
42343 function btn(id, toggle, handler){
42344 var xid = fid + '-'+ id ;
42348 cls : 'x-btn-icon x-edit-'+id,
42349 enableToggle:toggle !== false,
42350 scope: editor, // was editor...
42351 handler:handler||editor.relayBtnCmd,
42352 clickEvent:'mousedown',
42353 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42360 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
42362 // stop form submits
42363 tb.el.on('click', function(e){
42364 e.preventDefault(); // what does this do?
42367 if(!this.disable.font) { // && !Roo.isSafari){
42368 /* why no safari for fonts
42369 editor.fontSelect = tb.el.createChild({
42372 cls:'x-font-select',
42373 html: this.createFontOptions()
42376 editor.fontSelect.on('change', function(){
42377 var font = editor.fontSelect.dom.value;
42378 editor.relayCmd('fontname', font);
42379 editor.deferFocus();
42383 editor.fontSelect.dom,
42389 if(!this.disable.formats){
42390 this.formatCombo = new Roo.form.ComboBox({
42391 store: new Roo.data.SimpleStore({
42394 data : this.formats // from states.js
42398 //autoCreate : {tag: "div", size: "20"},
42399 displayField:'tag',
42403 triggerAction: 'all',
42404 emptyText:'Add tag',
42405 selectOnFocus:true,
42408 'select': function(c, r, i) {
42409 editor.insertTag(r.get('tag'));
42415 tb.addField(this.formatCombo);
42419 if(!this.disable.format){
42426 if(!this.disable.fontSize){
42431 btn('increasefontsize', false, editor.adjustFont),
42432 btn('decreasefontsize', false, editor.adjustFont)
42437 if(!this.disable.colors){
42440 id:editor.frameId +'-forecolor',
42441 cls:'x-btn-icon x-edit-forecolor',
42442 clickEvent:'mousedown',
42443 tooltip: this.buttonTips['forecolor'] || undefined,
42445 menu : new Roo.menu.ColorMenu({
42446 allowReselect: true,
42447 focus: Roo.emptyFn,
42450 selectHandler: function(cp, color){
42451 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
42452 editor.deferFocus();
42455 clickEvent:'mousedown'
42458 id:editor.frameId +'backcolor',
42459 cls:'x-btn-icon x-edit-backcolor',
42460 clickEvent:'mousedown',
42461 tooltip: this.buttonTips['backcolor'] || undefined,
42463 menu : new Roo.menu.ColorMenu({
42464 focus: Roo.emptyFn,
42467 allowReselect: true,
42468 selectHandler: function(cp, color){
42470 editor.execCmd('useCSS', false);
42471 editor.execCmd('hilitecolor', color);
42472 editor.execCmd('useCSS', true);
42473 editor.deferFocus();
42475 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
42476 Roo.isSafari || Roo.isIE ? '#'+color : color);
42477 editor.deferFocus();
42481 clickEvent:'mousedown'
42486 // now add all the items...
42489 if(!this.disable.alignments){
42492 btn('justifyleft'),
42493 btn('justifycenter'),
42494 btn('justifyright')
42498 //if(!Roo.isSafari){
42499 if(!this.disable.links){
42502 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
42506 if(!this.disable.lists){
42509 btn('insertorderedlist'),
42510 btn('insertunorderedlist')
42513 if(!this.disable.sourceEdit){
42516 btn('sourceedit', true, function(btn){
42517 this.toggleSourceEdit(btn.pressed);
42524 // special menu.. - needs to be tidied up..
42525 if (!this.disable.special) {
42528 cls: 'x-edit-none',
42534 for (var i =0; i < this.specialChars.length; i++) {
42535 smenu.menu.items.push({
42537 html: this.specialChars[i],
42538 handler: function(a,b) {
42539 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
42540 //editor.insertAtCursor(a.html);
42554 if (!this.disable.cleanStyles) {
42556 cls: 'x-btn-icon x-btn-clear',
42562 for (var i =0; i < this.cleanStyles.length; i++) {
42563 cmenu.menu.items.push({
42564 actiontype : this.cleanStyles[i],
42565 html: 'Remove ' + this.cleanStyles[i],
42566 handler: function(a,b) {
42569 var c = Roo.get(editor.doc.body);
42570 c.select('[style]').each(function(s) {
42571 s.dom.style.removeProperty(a.actiontype);
42582 if (!this.disable.specialElements) {
42585 cls: 'x-edit-none',
42590 for (var i =0; i < this.specialElements.length; i++) {
42591 semenu.menu.items.push(
42593 handler: function(a,b) {
42594 editor.insertAtCursor(this.ihtml);
42596 }, this.specialElements[i])
42608 for(var i =0; i< this.btns.length;i++) {
42609 var b = Roo.factory(this.btns[i],Roo.form);
42610 b.cls = 'x-edit-none';
42619 // disable everything...
42621 this.tb.items.each(function(item){
42622 if(item.id != editor.frameId+ '-sourceedit'){
42626 this.rendered = true;
42628 // the all the btns;
42629 editor.on('editorevent', this.updateToolbar, this);
42630 // other toolbars need to implement this..
42631 //editor.on('editmodechange', this.updateToolbar, this);
42637 * Protected method that will not generally be called directly. It triggers
42638 * a toolbar update by reading the markup state of the current selection in the editor.
42640 updateToolbar: function(){
42642 if(!this.editor.activated){
42643 this.editor.onFirstFocus();
42647 var btns = this.tb.items.map,
42648 doc = this.editor.doc,
42649 frameId = this.editor.frameId;
42651 if(!this.disable.font && !Roo.isSafari){
42653 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
42654 if(name != this.fontSelect.dom.value){
42655 this.fontSelect.dom.value = name;
42659 if(!this.disable.format){
42660 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
42661 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
42662 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
42664 if(!this.disable.alignments){
42665 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
42666 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
42667 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
42669 if(!Roo.isSafari && !this.disable.lists){
42670 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
42671 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
42674 var ans = this.editor.getAllAncestors();
42675 if (this.formatCombo) {
42678 var store = this.formatCombo.store;
42679 this.formatCombo.setValue("");
42680 for (var i =0; i < ans.length;i++) {
42681 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
42683 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
42691 // hides menus... - so this cant be on a menu...
42692 Roo.menu.MenuMgr.hideAll();
42694 //this.editorsyncValue();
42698 createFontOptions : function(){
42699 var buf = [], fs = this.fontFamilies, ff, lc;
42703 for(var i = 0, len = fs.length; i< len; i++){
42705 lc = ff.toLowerCase();
42707 '<option value="',lc,'" style="font-family:',ff,';"',
42708 (this.defaultFont == lc ? ' selected="true">' : '>'),
42713 return buf.join('');
42716 toggleSourceEdit : function(sourceEditMode){
42717 if(sourceEditMode === undefined){
42718 sourceEditMode = !this.sourceEditMode;
42720 this.sourceEditMode = sourceEditMode === true;
42721 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
42722 // just toggle the button?
42723 if(btn.pressed !== this.editor.sourceEditMode){
42724 btn.toggle(this.editor.sourceEditMode);
42728 if(this.sourceEditMode){
42729 this.tb.items.each(function(item){
42730 if(item.cmd != 'sourceedit'){
42736 if(this.initialized){
42737 this.tb.items.each(function(item){
42743 // tell the editor that it's been pressed..
42744 this.editor.toggleSourceEdit(sourceEditMode);
42748 * Object collection of toolbar tooltips for the buttons in the editor. The key
42749 * is the command id associated with that button and the value is a valid QuickTips object.
42754 title: 'Bold (Ctrl+B)',
42755 text: 'Make the selected text bold.',
42756 cls: 'x-html-editor-tip'
42759 title: 'Italic (Ctrl+I)',
42760 text: 'Make the selected text italic.',
42761 cls: 'x-html-editor-tip'
42769 title: 'Bold (Ctrl+B)',
42770 text: 'Make the selected text bold.',
42771 cls: 'x-html-editor-tip'
42774 title: 'Italic (Ctrl+I)',
42775 text: 'Make the selected text italic.',
42776 cls: 'x-html-editor-tip'
42779 title: 'Underline (Ctrl+U)',
42780 text: 'Underline the selected text.',
42781 cls: 'x-html-editor-tip'
42783 increasefontsize : {
42784 title: 'Grow Text',
42785 text: 'Increase the font size.',
42786 cls: 'x-html-editor-tip'
42788 decreasefontsize : {
42789 title: 'Shrink Text',
42790 text: 'Decrease the font size.',
42791 cls: 'x-html-editor-tip'
42794 title: 'Text Highlight Color',
42795 text: 'Change the background color of the selected text.',
42796 cls: 'x-html-editor-tip'
42799 title: 'Font Color',
42800 text: 'Change the color of the selected text.',
42801 cls: 'x-html-editor-tip'
42804 title: 'Align Text Left',
42805 text: 'Align text to the left.',
42806 cls: 'x-html-editor-tip'
42809 title: 'Center Text',
42810 text: 'Center text in the editor.',
42811 cls: 'x-html-editor-tip'
42814 title: 'Align Text Right',
42815 text: 'Align text to the right.',
42816 cls: 'x-html-editor-tip'
42818 insertunorderedlist : {
42819 title: 'Bullet List',
42820 text: 'Start a bulleted list.',
42821 cls: 'x-html-editor-tip'
42823 insertorderedlist : {
42824 title: 'Numbered List',
42825 text: 'Start a numbered list.',
42826 cls: 'x-html-editor-tip'
42829 title: 'Hyperlink',
42830 text: 'Make the selected text a hyperlink.',
42831 cls: 'x-html-editor-tip'
42834 title: 'Source Edit',
42835 text: 'Switch to source editing mode.',
42836 cls: 'x-html-editor-tip'
42840 onDestroy : function(){
42843 this.tb.items.each(function(item){
42845 item.menu.removeAll();
42847 item.menu.el.destroy();
42855 onFirstFocus: function() {
42856 this.tb.items.each(function(item){
42865 // <script type="text/javascript">
42868 * Ext JS Library 1.1.1
42869 * Copyright(c) 2006-2007, Ext JS, LLC.
42876 * @class Roo.form.HtmlEditor.ToolbarContext
42881 new Roo.form.HtmlEditor({
42884 { xtype: 'ToolbarStandard', styles : {} }
42885 { xtype: 'ToolbarContext', disable : {} }
42891 * @config : {Object} disable List of elements to disable.. (not done yet.)
42892 * @config : {Object} styles Map of styles available.
42896 Roo.form.HtmlEditor.ToolbarContext = function(config)
42899 Roo.apply(this, config);
42900 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42901 // dont call parent... till later.
42902 this.styles = this.styles || {};
42907 Roo.form.HtmlEditor.ToolbarContext.types = {
42919 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
42985 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
42990 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
43000 style : 'fontFamily',
43001 displayField: 'display',
43002 optname : 'font-family',
43051 // should we really allow this??
43052 // should this just be
43063 style : 'fontFamily',
43064 displayField: 'display',
43065 optname : 'font-family',
43072 style : 'fontFamily',
43073 displayField: 'display',
43074 optname : 'font-family',
43081 style : 'fontFamily',
43082 displayField: 'display',
43083 optname : 'font-family',
43094 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
43095 Roo.form.HtmlEditor.ToolbarContext.stores = false;
43097 Roo.form.HtmlEditor.ToolbarContext.options = {
43099 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
43100 [ 'Courier New', 'Courier New'],
43101 [ 'Tahoma', 'Tahoma'],
43102 [ 'Times New Roman,serif', 'Times'],
43103 [ 'Verdana','Verdana' ]
43107 // fixme - these need to be configurable..
43110 Roo.form.HtmlEditor.ToolbarContext.types
43113 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
43121 * @cfg {Object} disable List of toolbar elements to disable
43126 * @cfg {Object} styles List of styles
43127 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
43129 * These must be defined in the page, so they get rendered correctly..
43140 init : function(editor)
43142 this.editor = editor;
43145 var fid = editor.frameId;
43147 function btn(id, toggle, handler){
43148 var xid = fid + '-'+ id ;
43152 cls : 'x-btn-icon x-edit-'+id,
43153 enableToggle:toggle !== false,
43154 scope: editor, // was editor...
43155 handler:handler||editor.relayBtnCmd,
43156 clickEvent:'mousedown',
43157 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43161 // create a new element.
43162 var wdiv = editor.wrap.createChild({
43164 }, editor.wrap.dom.firstChild.nextSibling, true);
43166 // can we do this more than once??
43168 // stop form submits
43171 // disable everything...
43172 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43173 this.toolbars = {};
43175 for (var i in ty) {
43177 this.toolbars[i] = this.buildToolbar(ty[i],i);
43179 this.tb = this.toolbars.BODY;
43181 this.buildFooter();
43182 this.footer.show();
43183 editor.on('hide', function( ) { this.footer.hide() }, this);
43184 editor.on('show', function( ) { this.footer.show() }, this);
43187 this.rendered = true;
43189 // the all the btns;
43190 editor.on('editorevent', this.updateToolbar, this);
43191 // other toolbars need to implement this..
43192 //editor.on('editmodechange', this.updateToolbar, this);
43198 * Protected method that will not generally be called directly. It triggers
43199 * a toolbar update by reading the markup state of the current selection in the editor.
43201 updateToolbar: function(editor,ev,sel){
43204 // capture mouse up - this is handy for selecting images..
43205 // perhaps should go somewhere else...
43206 if(!this.editor.activated){
43207 this.editor.onFirstFocus();
43211 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
43212 // selectNode - might want to handle IE?
43214 (ev.type == 'mouseup' || ev.type == 'click' ) &&
43215 ev.target && ev.target.tagName == 'IMG') {
43216 // they have click on an image...
43217 // let's see if we can change the selection...
43220 var nodeRange = sel.ownerDocument.createRange();
43222 nodeRange.selectNode(sel);
43224 nodeRange.selectNodeContents(sel);
43226 //nodeRange.collapse(true);
43227 var s = editor.win.getSelection();
43228 s.removeAllRanges();
43229 s.addRange(nodeRange);
43233 var updateFooter = sel ? false : true;
43236 var ans = this.editor.getAllAncestors();
43239 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43242 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
43243 sel = sel ? sel : this.editor.doc.body;
43244 sel = sel.tagName.length ? sel : this.editor.doc.body;
43247 // pick a menu that exists..
43248 var tn = sel.tagName.toUpperCase();
43249 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
43251 tn = sel.tagName.toUpperCase();
43253 var lastSel = this.tb.selectedNode
43255 this.tb.selectedNode = sel;
43257 // if current menu does not match..
43258 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
43261 ///console.log("show: " + tn);
43262 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
43265 this.tb.items.first().el.innerHTML = tn + ': ';
43268 // update attributes
43269 if (this.tb.fields) {
43270 this.tb.fields.each(function(e) {
43272 e.setValue(sel.style[e.stylename]);
43275 e.setValue(sel.getAttribute(e.attrname));
43279 var hasStyles = false;
43280 for(var i in this.styles) {
43287 var st = this.tb.fields.item(0);
43289 st.store.removeAll();
43292 var cn = sel.className.split(/\s+/);
43295 if (this.styles['*']) {
43297 Roo.each(this.styles['*'], function(v) {
43298 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43301 if (this.styles[tn]) {
43302 Roo.each(this.styles[tn], function(v) {
43303 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43307 st.store.loadData(avs);
43311 // flag our selected Node.
43312 this.tb.selectedNode = sel;
43315 Roo.menu.MenuMgr.hideAll();
43319 if (!updateFooter) {
43320 //this.footDisp.dom.innerHTML = '';
43323 // update the footer
43327 this.footerEls = ans.reverse();
43328 Roo.each(this.footerEls, function(a,i) {
43329 if (!a) { return; }
43330 html += html.length ? ' > ' : '';
43332 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
43337 var sz = this.footDisp.up('td').getSize();
43338 this.footDisp.dom.style.width = (sz.width -10) + 'px';
43339 this.footDisp.dom.style.marginLeft = '5px';
43341 this.footDisp.dom.style.overflow = 'hidden';
43343 this.footDisp.dom.innerHTML = html;
43345 //this.editorsyncValue();
43352 onDestroy : function(){
43355 this.tb.items.each(function(item){
43357 item.menu.removeAll();
43359 item.menu.el.destroy();
43367 onFirstFocus: function() {
43368 // need to do this for all the toolbars..
43369 this.tb.items.each(function(item){
43373 buildToolbar: function(tlist, nm)
43375 var editor = this.editor;
43376 // create a new element.
43377 var wdiv = editor.wrap.createChild({
43379 }, editor.wrap.dom.firstChild.nextSibling, true);
43382 var tb = new Roo.Toolbar(wdiv);
43385 tb.add(nm+ ": ");
43388 for(var i in this.styles) {
43393 if (styles && styles.length) {
43395 // this needs a multi-select checkbox...
43396 tb.addField( new Roo.form.ComboBox({
43397 store: new Roo.data.SimpleStore({
43399 fields: ['val', 'selected'],
43402 name : '-roo-edit-className',
43403 attrname : 'className',
43404 displayField: 'val',
43408 triggerAction: 'all',
43409 emptyText:'Select Style',
43410 selectOnFocus:true,
43413 'select': function(c, r, i) {
43414 // initial support only for on class per el..
43415 tb.selectedNode.className = r ? r.get('val') : '';
43416 editor.syncValue();
43423 var tbc = Roo.form.HtmlEditor.ToolbarContext;
43424 var tbops = tbc.options;
43426 for (var i in tlist) {
43428 var item = tlist[i];
43429 tb.add(item.title + ": ");
43432 //optname == used so you can configure the options available..
43433 var opts = item.opts ? item.opts : false;
43434 if (item.optname) {
43435 opts = tbops[item.optname];
43440 // opts == pulldown..
43441 tb.addField( new Roo.form.ComboBox({
43442 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
43444 fields: ['val', 'display'],
43447 name : '-roo-edit-' + i,
43449 stylename : item.style ? item.style : false,
43450 displayField: item.displayField ? item.displayField : 'val',
43451 valueField : 'val',
43453 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
43455 triggerAction: 'all',
43456 emptyText:'Select',
43457 selectOnFocus:true,
43458 width: item.width ? item.width : 130,
43460 'select': function(c, r, i) {
43462 tb.selectedNode.style[c.stylename] = r.get('val');
43465 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
43474 tb.addField( new Roo.form.TextField({
43477 //allowBlank:false,
43482 tb.addField( new Roo.form.TextField({
43483 name: '-roo-edit-' + i,
43490 'change' : function(f, nv, ov) {
43491 tb.selectedNode.setAttribute(f.attrname, nv);
43500 text: 'Remove Tag',
43503 click : function ()
43506 // undo does not work.
43508 var sn = tb.selectedNode;
43510 var pn = sn.parentNode;
43512 var stn = sn.childNodes[0];
43513 var en = sn.childNodes[sn.childNodes.length - 1 ];
43514 while (sn.childNodes.length) {
43515 var node = sn.childNodes[0];
43516 sn.removeChild(node);
43518 pn.insertBefore(node, sn);
43521 pn.removeChild(sn);
43522 var range = editor.createRange();
43524 range.setStart(stn,0);
43525 range.setEnd(en,0); //????
43526 //range.selectNode(sel);
43529 var selection = editor.getSelection();
43530 selection.removeAllRanges();
43531 selection.addRange(range);
43535 //_this.updateToolbar(null, null, pn);
43536 _this.updateToolbar(null, null, null);
43537 _this.footDisp.dom.innerHTML = '';
43547 tb.el.on('click', function(e){
43548 e.preventDefault(); // what does this do?
43550 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
43553 // dont need to disable them... as they will get hidden
43558 buildFooter : function()
43561 var fel = this.editor.wrap.createChild();
43562 this.footer = new Roo.Toolbar(fel);
43563 // toolbar has scrolly on left / right?
43564 var footDisp= new Roo.Toolbar.Fill();
43570 handler : function() {
43571 _t.footDisp.scrollTo('left',0,true)
43575 this.footer.add( footDisp );
43580 handler : function() {
43582 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
43586 var fel = Roo.get(footDisp.el);
43587 fel.addClass('x-editor-context');
43588 this.footDispWrap = fel;
43589 this.footDispWrap.overflow = 'hidden';
43591 this.footDisp = fel.createChild();
43592 this.footDispWrap.on('click', this.onContextClick, this)
43596 onContextClick : function (ev,dom)
43598 ev.preventDefault();
43599 var cn = dom.className;
43601 if (!cn.match(/x-ed-loc-/)) {
43604 var n = cn.split('-').pop();
43605 var ans = this.footerEls;
43609 var range = this.editor.createRange();
43611 range.selectNodeContents(sel);
43612 //range.selectNode(sel);
43615 var selection = this.editor.getSelection();
43616 selection.removeAllRanges();
43617 selection.addRange(range);
43621 this.updateToolbar(null, null, sel);
43638 * Ext JS Library 1.1.1
43639 * Copyright(c) 2006-2007, Ext JS, LLC.
43641 * Originally Released Under LGPL - original licence link has changed is not relivant.
43644 * <script type="text/javascript">
43648 * @class Roo.form.BasicForm
43649 * @extends Roo.util.Observable
43650 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
43652 * @param {String/HTMLElement/Roo.Element} el The form element or its id
43653 * @param {Object} config Configuration options
43655 Roo.form.BasicForm = function(el, config){
43656 this.allItems = [];
43657 this.childForms = [];
43658 Roo.apply(this, config);
43660 * The Roo.form.Field items in this form.
43661 * @type MixedCollection
43665 this.items = new Roo.util.MixedCollection(false, function(o){
43666 return o.id || (o.id = Roo.id());
43670 * @event beforeaction
43671 * Fires before any action is performed. Return false to cancel the action.
43672 * @param {Form} this
43673 * @param {Action} action The action to be performed
43675 beforeaction: true,
43677 * @event actionfailed
43678 * Fires when an action fails.
43679 * @param {Form} this
43680 * @param {Action} action The action that failed
43682 actionfailed : true,
43684 * @event actioncomplete
43685 * Fires when an action is completed.
43686 * @param {Form} this
43687 * @param {Action} action The action that completed
43689 actioncomplete : true
43694 Roo.form.BasicForm.superclass.constructor.call(this);
43697 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
43699 * @cfg {String} method
43700 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
43703 * @cfg {DataReader} reader
43704 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
43705 * This is optional as there is built-in support for processing JSON.
43708 * @cfg {DataReader} errorReader
43709 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
43710 * This is completely optional as there is built-in support for processing JSON.
43713 * @cfg {String} url
43714 * The URL to use for form actions if one isn't supplied in the action options.
43717 * @cfg {Boolean} fileUpload
43718 * Set to true if this form is a file upload.
43722 * @cfg {Object} baseParams
43723 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
43728 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
43733 activeAction : null,
43736 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
43737 * or setValues() data instead of when the form was first created.
43739 trackResetOnLoad : false,
43743 * childForms - used for multi-tab forms
43746 childForms : false,
43749 * allItems - full list of fields.
43755 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
43756 * element by passing it or its id or mask the form itself by passing in true.
43759 waitMsgTarget : false,
43762 initEl : function(el){
43763 this.el = Roo.get(el);
43764 this.id = this.el.id || Roo.id();
43765 this.el.on('submit', this.onSubmit, this);
43766 this.el.addClass('x-form');
43770 onSubmit : function(e){
43775 * Returns true if client-side validation on the form is successful.
43778 isValid : function(){
43780 this.items.each(function(f){
43789 * Returns true if any fields in this form have changed since their original load.
43792 isDirty : function(){
43794 this.items.each(function(f){
43804 * Performs a predefined action (submit or load) or custom actions you define on this form.
43805 * @param {String} actionName The name of the action type
43806 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
43807 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
43808 * accept other config options):
43810 Property Type Description
43811 ---------------- --------------- ----------------------------------------------------------------------------------
43812 url String The url for the action (defaults to the form's url)
43813 method String The form method to use (defaults to the form's method, or POST if not defined)
43814 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
43815 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
43816 validate the form on the client (defaults to false)
43818 * @return {BasicForm} this
43820 doAction : function(action, options){
43821 if(typeof action == 'string'){
43822 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
43824 if(this.fireEvent('beforeaction', this, action) !== false){
43825 this.beforeAction(action);
43826 action.run.defer(100, action);
43832 * Shortcut to do a submit action.
43833 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43834 * @return {BasicForm} this
43836 submit : function(options){
43837 this.doAction('submit', options);
43842 * Shortcut to do a load action.
43843 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43844 * @return {BasicForm} this
43846 load : function(options){
43847 this.doAction('load', options);
43852 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
43853 * @param {Record} record The record to edit
43854 * @return {BasicForm} this
43856 updateRecord : function(record){
43857 record.beginEdit();
43858 var fs = record.fields;
43859 fs.each(function(f){
43860 var field = this.findField(f.name);
43862 record.set(f.name, field.getValue());
43870 * Loads an Roo.data.Record into this form.
43871 * @param {Record} record The record to load
43872 * @return {BasicForm} this
43874 loadRecord : function(record){
43875 this.setValues(record.data);
43880 beforeAction : function(action){
43881 var o = action.options;
43884 if(this.waitMsgTarget === true){
43885 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
43886 }else if(this.waitMsgTarget){
43887 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
43888 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
43890 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
43896 afterAction : function(action, success){
43897 this.activeAction = null;
43898 var o = action.options;
43900 if(this.waitMsgTarget === true){
43902 }else if(this.waitMsgTarget){
43903 this.waitMsgTarget.unmask();
43905 Roo.MessageBox.updateProgress(1);
43906 Roo.MessageBox.hide();
43913 Roo.callback(o.success, o.scope, [this, action]);
43914 this.fireEvent('actioncomplete', this, action);
43918 // failure condition..
43919 // we have a scenario where updates need confirming.
43920 // eg. if a locking scenario exists..
43921 // we look for { errors : { needs_confirm : true }} in the response.
43923 (typeof(action.result) != 'undefined') &&
43924 (typeof(action.result.errors) != 'undefined') &&
43925 (typeof(action.result.errors.needs_confirm) != 'undefined')
43928 Roo.MessageBox.confirm(
43929 "Change requires confirmation",
43930 action.result.errorMsg,
43935 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
43945 Roo.callback(o.failure, o.scope, [this, action]);
43946 // show an error message if no failed handler is set..
43947 if (!this.hasListener('actionfailed')) {
43948 Roo.MessageBox.alert("Error",
43949 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
43950 action.result.errorMsg :
43951 "Saving Failed, please check your entries or try again"
43955 this.fireEvent('actionfailed', this, action);
43961 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
43962 * @param {String} id The value to search for
43965 findField : function(id){
43966 var field = this.items.get(id);
43968 this.items.each(function(f){
43969 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
43975 return field || null;
43979 * Add a secondary form to this one,
43980 * Used to provide tabbed forms. One form is primary, with hidden values
43981 * which mirror the elements from the other forms.
43983 * @param {Roo.form.Form} form to add.
43986 addForm : function(form)
43989 if (this.childForms.indexOf(form) > -1) {
43993 this.childForms.push(form);
43995 Roo.each(form.allItems, function (fe) {
43997 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
43998 if (this.findField(n)) { // already added..
44001 var add = new Roo.form.Hidden({
44004 add.render(this.el);
44011 * Mark fields in this form invalid in bulk.
44012 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
44013 * @return {BasicForm} this
44015 markInvalid : function(errors){
44016 if(errors instanceof Array){
44017 for(var i = 0, len = errors.length; i < len; i++){
44018 var fieldError = errors[i];
44019 var f = this.findField(fieldError.id);
44021 f.markInvalid(fieldError.msg);
44027 if(typeof errors[id] != 'function' && (field = this.findField(id))){
44028 field.markInvalid(errors[id]);
44032 Roo.each(this.childForms || [], function (f) {
44033 f.markInvalid(errors);
44040 * Set values for fields in this form in bulk.
44041 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
44042 * @return {BasicForm} this
44044 setValues : function(values){
44045 if(values instanceof Array){ // array of objects
44046 for(var i = 0, len = values.length; i < len; i++){
44048 var f = this.findField(v.id);
44050 f.setValue(v.value);
44051 if(this.trackResetOnLoad){
44052 f.originalValue = f.getValue();
44056 }else{ // object hash
44059 if(typeof values[id] != 'function' && (field = this.findField(id))){
44061 if (field.setFromData &&
44062 field.valueField &&
44063 field.displayField &&
44064 // combos' with local stores can
44065 // be queried via setValue()
44066 // to set their value..
44067 (field.store && !field.store.isLocal)
44071 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44072 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44073 field.setFromData(sd);
44076 field.setValue(values[id]);
44080 if(this.trackResetOnLoad){
44081 field.originalValue = field.getValue();
44087 Roo.each(this.childForms || [], function (f) {
44088 f.setValues(values);
44095 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
44096 * they are returned as an array.
44097 * @param {Boolean} asString
44100 getValues : function(asString){
44101 if (this.childForms) {
44102 // copy values from the child forms
44103 Roo.each(this.childForms, function (f) {
44104 this.setValues(f.getValues());
44110 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
44111 if(asString === true){
44114 return Roo.urlDecode(fs);
44118 * Returns the fields in this form as an object with key/value pairs.
44119 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
44122 getFieldValues : function(with_hidden)
44124 if (this.childForms) {
44125 // copy values from the child forms
44126 // should this call getFieldValues - probably not as we do not currently copy
44127 // hidden fields when we generate..
44128 Roo.each(this.childForms, function (f) {
44129 this.setValues(f.getValues());
44134 this.items.each(function(f){
44135 if (!f.getName()) {
44138 var v = f.getValue();
44139 if (f.inputType =='radio') {
44140 if (typeof(ret[f.getName()]) == 'undefined') {
44141 ret[f.getName()] = ''; // empty..
44144 if (!f.el.dom.checked) {
44148 v = f.el.dom.value;
44152 // not sure if this supported any more..
44153 if ((typeof(v) == 'object') && f.getRawValue) {
44154 v = f.getRawValue() ; // dates..
44156 // combo boxes where name != hiddenName...
44157 if (f.name != f.getName()) {
44158 ret[f.name] = f.getRawValue();
44160 ret[f.getName()] = v;
44167 * Clears all invalid messages in this form.
44168 * @return {BasicForm} this
44170 clearInvalid : function(){
44171 this.items.each(function(f){
44175 Roo.each(this.childForms || [], function (f) {
44184 * Resets this form.
44185 * @return {BasicForm} this
44187 reset : function(){
44188 this.items.each(function(f){
44192 Roo.each(this.childForms || [], function (f) {
44201 * Add Roo.form components to this form.
44202 * @param {Field} field1
44203 * @param {Field} field2 (optional)
44204 * @param {Field} etc (optional)
44205 * @return {BasicForm} this
44208 this.items.addAll(Array.prototype.slice.call(arguments, 0));
44214 * Removes a field from the items collection (does NOT remove its markup).
44215 * @param {Field} field
44216 * @return {BasicForm} this
44218 remove : function(field){
44219 this.items.remove(field);
44224 * Looks at the fields in this form, checks them for an id attribute,
44225 * and calls applyTo on the existing dom element with that id.
44226 * @return {BasicForm} this
44228 render : function(){
44229 this.items.each(function(f){
44230 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
44238 * Calls {@link Ext#apply} for all fields in this form with the passed object.
44239 * @param {Object} values
44240 * @return {BasicForm} this
44242 applyToFields : function(o){
44243 this.items.each(function(f){
44250 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
44251 * @param {Object} values
44252 * @return {BasicForm} this
44254 applyIfToFields : function(o){
44255 this.items.each(function(f){
44263 Roo.BasicForm = Roo.form.BasicForm;/*
44265 * Ext JS Library 1.1.1
44266 * Copyright(c) 2006-2007, Ext JS, LLC.
44268 * Originally Released Under LGPL - original licence link has changed is not relivant.
44271 * <script type="text/javascript">
44275 * @class Roo.form.Form
44276 * @extends Roo.form.BasicForm
44277 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
44279 * @param {Object} config Configuration options
44281 Roo.form.Form = function(config){
44283 if (config.items) {
44284 xitems = config.items;
44285 delete config.items;
44289 Roo.form.Form.superclass.constructor.call(this, null, config);
44290 this.url = this.url || this.action;
44292 this.root = new Roo.form.Layout(Roo.applyIf({
44296 this.active = this.root;
44298 * Array of all the buttons that have been added to this form via {@link addButton}
44302 this.allItems = [];
44305 * @event clientvalidation
44306 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
44307 * @param {Form} this
44308 * @param {Boolean} valid true if the form has passed client-side validation
44310 clientvalidation: true,
44313 * Fires when the form is rendered
44314 * @param {Roo.form.Form} form
44319 if (this.progressUrl) {
44320 // push a hidden field onto the list of fields..
44324 name : 'UPLOAD_IDENTIFIER'
44329 Roo.each(xitems, this.addxtype, this);
44335 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
44337 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
44340 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
44343 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
44345 buttonAlign:'center',
44348 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
44353 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
44354 * This property cascades to child containers if not set.
44359 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
44360 * fires a looping event with that state. This is required to bind buttons to the valid
44361 * state using the config value formBind:true on the button.
44363 monitorValid : false,
44366 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
44371 * @cfg {String} progressUrl - Url to return progress data
44374 progressUrl : false,
44377 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
44378 * fields are added and the column is closed. If no fields are passed the column remains open
44379 * until end() is called.
44380 * @param {Object} config The config to pass to the column
44381 * @param {Field} field1 (optional)
44382 * @param {Field} field2 (optional)
44383 * @param {Field} etc (optional)
44384 * @return Column The column container object
44386 column : function(c){
44387 var col = new Roo.form.Column(c);
44389 if(arguments.length > 1){ // duplicate code required because of Opera
44390 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44397 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
44398 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
44399 * until end() is called.
44400 * @param {Object} config The config to pass to the fieldset
44401 * @param {Field} field1 (optional)
44402 * @param {Field} field2 (optional)
44403 * @param {Field} etc (optional)
44404 * @return FieldSet The fieldset container object
44406 fieldset : function(c){
44407 var fs = new Roo.form.FieldSet(c);
44409 if(arguments.length > 1){ // duplicate code required because of Opera
44410 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44417 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
44418 * fields are added and the container is closed. If no fields are passed the container remains open
44419 * until end() is called.
44420 * @param {Object} config The config to pass to the Layout
44421 * @param {Field} field1 (optional)
44422 * @param {Field} field2 (optional)
44423 * @param {Field} etc (optional)
44424 * @return Layout The container object
44426 container : function(c){
44427 var l = new Roo.form.Layout(c);
44429 if(arguments.length > 1){ // duplicate code required because of Opera
44430 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44437 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
44438 * @param {Object} container A Roo.form.Layout or subclass of Layout
44439 * @return {Form} this
44441 start : function(c){
44442 // cascade label info
44443 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
44444 this.active.stack.push(c);
44445 c.ownerCt = this.active;
44451 * Closes the current open container
44452 * @return {Form} this
44455 if(this.active == this.root){
44458 this.active = this.active.ownerCt;
44463 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
44464 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
44465 * as the label of the field.
44466 * @param {Field} field1
44467 * @param {Field} field2 (optional)
44468 * @param {Field} etc. (optional)
44469 * @return {Form} this
44472 this.active.stack.push.apply(this.active.stack, arguments);
44473 this.allItems.push.apply(this.allItems,arguments);
44475 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
44476 if(a[i].isFormField){
44481 Roo.form.Form.superclass.add.apply(this, r);
44491 * Find any element that has been added to a form, using it's ID or name
44492 * This can include framesets, columns etc. along with regular fields..
44493 * @param {String} id - id or name to find.
44495 * @return {Element} e - or false if nothing found.
44497 findbyId : function(id)
44503 Roo.each(this.allItems, function(f){
44504 if (f.id == id || f.name == id ){
44515 * Render this form into the passed container. This should only be called once!
44516 * @param {String/HTMLElement/Element} container The element this component should be rendered into
44517 * @return {Form} this
44519 render : function(ct)
44525 var o = this.autoCreate || {
44527 method : this.method || 'POST',
44528 id : this.id || Roo.id()
44530 this.initEl(ct.createChild(o));
44532 this.root.render(this.el);
44536 this.items.each(function(f){
44537 f.render('x-form-el-'+f.id);
44540 if(this.buttons.length > 0){
44541 // tables are required to maintain order and for correct IE layout
44542 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
44543 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
44544 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
44546 var tr = tb.getElementsByTagName('tr')[0];
44547 for(var i = 0, len = this.buttons.length; i < len; i++) {
44548 var b = this.buttons[i];
44549 var td = document.createElement('td');
44550 td.className = 'x-form-btn-td';
44551 b.render(tr.appendChild(td));
44554 if(this.monitorValid){ // initialize after render
44555 this.startMonitoring();
44557 this.fireEvent('rendered', this);
44562 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
44563 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
44564 * object or a valid Roo.DomHelper element config
44565 * @param {Function} handler The function called when the button is clicked
44566 * @param {Object} scope (optional) The scope of the handler function
44567 * @return {Roo.Button}
44569 addButton : function(config, handler, scope){
44573 minWidth: this.minButtonWidth,
44576 if(typeof config == "string"){
44579 Roo.apply(bc, config);
44581 var btn = new Roo.Button(null, bc);
44582 this.buttons.push(btn);
44587 * Adds a series of form elements (using the xtype property as the factory method.
44588 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
44589 * @param {Object} config
44592 addxtype : function()
44594 var ar = Array.prototype.slice.call(arguments, 0);
44596 for(var i = 0; i < ar.length; i++) {
44598 continue; // skip -- if this happends something invalid got sent, we
44599 // should ignore it, as basically that interface element will not show up
44600 // and that should be pretty obvious!!
44603 if (Roo.form[ar[i].xtype]) {
44605 var fe = Roo.factory(ar[i], Roo.form);
44611 fe.store.form = this;
44616 this.allItems.push(fe);
44617 if (fe.items && fe.addxtype) {
44618 fe.addxtype.apply(fe, fe.items);
44628 // console.log('adding ' + ar[i].xtype);
44630 if (ar[i].xtype == 'Button') {
44631 //console.log('adding button');
44632 //console.log(ar[i]);
44633 this.addButton(ar[i]);
44634 this.allItems.push(fe);
44638 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
44639 alert('end is not supported on xtype any more, use items');
44641 // //console.log('adding end');
44649 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
44650 * option "monitorValid"
44652 startMonitoring : function(){
44655 Roo.TaskMgr.start({
44656 run : this.bindHandler,
44657 interval : this.monitorPoll || 200,
44664 * Stops monitoring of the valid state of this form
44666 stopMonitoring : function(){
44667 this.bound = false;
44671 bindHandler : function(){
44673 return false; // stops binding
44676 this.items.each(function(f){
44677 if(!f.isValid(true)){
44682 for(var i = 0, len = this.buttons.length; i < len; i++){
44683 var btn = this.buttons[i];
44684 if(btn.formBind === true && btn.disabled === valid){
44685 btn.setDisabled(!valid);
44688 this.fireEvent('clientvalidation', this, valid);
44702 Roo.Form = Roo.form.Form;
44705 * Ext JS Library 1.1.1
44706 * Copyright(c) 2006-2007, Ext JS, LLC.
44708 * Originally Released Under LGPL - original licence link has changed is not relivant.
44711 * <script type="text/javascript">
44714 // as we use this in bootstrap.
44715 Roo.namespace('Roo.form');
44717 * @class Roo.form.Action
44718 * Internal Class used to handle form actions
44720 * @param {Roo.form.BasicForm} el The form element or its id
44721 * @param {Object} config Configuration options
44726 // define the action interface
44727 Roo.form.Action = function(form, options){
44729 this.options = options || {};
44732 * Client Validation Failed
44735 Roo.form.Action.CLIENT_INVALID = 'client';
44737 * Server Validation Failed
44740 Roo.form.Action.SERVER_INVALID = 'server';
44742 * Connect to Server Failed
44745 Roo.form.Action.CONNECT_FAILURE = 'connect';
44747 * Reading Data from Server Failed
44750 Roo.form.Action.LOAD_FAILURE = 'load';
44752 Roo.form.Action.prototype = {
44754 failureType : undefined,
44755 response : undefined,
44756 result : undefined,
44758 // interface method
44759 run : function(options){
44763 // interface method
44764 success : function(response){
44768 // interface method
44769 handleResponse : function(response){
44773 // default connection failure
44774 failure : function(response){
44776 this.response = response;
44777 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44778 this.form.afterAction(this, false);
44781 processResponse : function(response){
44782 this.response = response;
44783 if(!response.responseText){
44786 this.result = this.handleResponse(response);
44787 return this.result;
44790 // utility functions used internally
44791 getUrl : function(appendParams){
44792 var url = this.options.url || this.form.url || this.form.el.dom.action;
44794 var p = this.getParams();
44796 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
44802 getMethod : function(){
44803 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
44806 getParams : function(){
44807 var bp = this.form.baseParams;
44808 var p = this.options.params;
44810 if(typeof p == "object"){
44811 p = Roo.urlEncode(Roo.applyIf(p, bp));
44812 }else if(typeof p == 'string' && bp){
44813 p += '&' + Roo.urlEncode(bp);
44816 p = Roo.urlEncode(bp);
44821 createCallback : function(){
44823 success: this.success,
44824 failure: this.failure,
44826 timeout: (this.form.timeout*1000),
44827 upload: this.form.fileUpload ? this.success : undefined
44832 Roo.form.Action.Submit = function(form, options){
44833 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
44836 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
44839 haveProgress : false,
44840 uploadComplete : false,
44842 // uploadProgress indicator.
44843 uploadProgress : function()
44845 if (!this.form.progressUrl) {
44849 if (!this.haveProgress) {
44850 Roo.MessageBox.progress("Uploading", "Uploading");
44852 if (this.uploadComplete) {
44853 Roo.MessageBox.hide();
44857 this.haveProgress = true;
44859 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
44861 var c = new Roo.data.Connection();
44863 url : this.form.progressUrl,
44868 success : function(req){
44869 //console.log(data);
44873 rdata = Roo.decode(req.responseText)
44875 Roo.log("Invalid data from server..");
44879 if (!rdata || !rdata.success) {
44881 Roo.MessageBox.alert(Roo.encode(rdata));
44884 var data = rdata.data;
44886 if (this.uploadComplete) {
44887 Roo.MessageBox.hide();
44892 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
44893 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
44896 this.uploadProgress.defer(2000,this);
44899 failure: function(data) {
44900 Roo.log('progress url failed ');
44911 // run get Values on the form, so it syncs any secondary forms.
44912 this.form.getValues();
44914 var o = this.options;
44915 var method = this.getMethod();
44916 var isPost = method == 'POST';
44917 if(o.clientValidation === false || this.form.isValid()){
44919 if (this.form.progressUrl) {
44920 this.form.findField('UPLOAD_IDENTIFIER').setValue(
44921 (new Date() * 1) + '' + Math.random());
44926 Roo.Ajax.request(Roo.apply(this.createCallback(), {
44927 form:this.form.el.dom,
44928 url:this.getUrl(!isPost),
44930 params:isPost ? this.getParams() : null,
44931 isUpload: this.form.fileUpload
44934 this.uploadProgress();
44936 }else if (o.clientValidation !== false){ // client validation failed
44937 this.failureType = Roo.form.Action.CLIENT_INVALID;
44938 this.form.afterAction(this, false);
44942 success : function(response)
44944 this.uploadComplete= true;
44945 if (this.haveProgress) {
44946 Roo.MessageBox.hide();
44950 var result = this.processResponse(response);
44951 if(result === true || result.success){
44952 this.form.afterAction(this, true);
44956 this.form.markInvalid(result.errors);
44957 this.failureType = Roo.form.Action.SERVER_INVALID;
44959 this.form.afterAction(this, false);
44961 failure : function(response)
44963 this.uploadComplete= true;
44964 if (this.haveProgress) {
44965 Roo.MessageBox.hide();
44968 this.response = response;
44969 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44970 this.form.afterAction(this, false);
44973 handleResponse : function(response){
44974 if(this.form.errorReader){
44975 var rs = this.form.errorReader.read(response);
44978 for(var i = 0, len = rs.records.length; i < len; i++) {
44979 var r = rs.records[i];
44980 errors[i] = r.data;
44983 if(errors.length < 1){
44987 success : rs.success,
44993 ret = Roo.decode(response.responseText);
44997 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
45007 Roo.form.Action.Load = function(form, options){
45008 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
45009 this.reader = this.form.reader;
45012 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
45017 Roo.Ajax.request(Roo.apply(
45018 this.createCallback(), {
45019 method:this.getMethod(),
45020 url:this.getUrl(false),
45021 params:this.getParams()
45025 success : function(response){
45027 var result = this.processResponse(response);
45028 if(result === true || !result.success || !result.data){
45029 this.failureType = Roo.form.Action.LOAD_FAILURE;
45030 this.form.afterAction(this, false);
45033 this.form.clearInvalid();
45034 this.form.setValues(result.data);
45035 this.form.afterAction(this, true);
45038 handleResponse : function(response){
45039 if(this.form.reader){
45040 var rs = this.form.reader.read(response);
45041 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
45043 success : rs.success,
45047 return Roo.decode(response.responseText);
45051 Roo.form.Action.ACTION_TYPES = {
45052 'load' : Roo.form.Action.Load,
45053 'submit' : Roo.form.Action.Submit
45056 * Ext JS Library 1.1.1
45057 * Copyright(c) 2006-2007, Ext JS, LLC.
45059 * Originally Released Under LGPL - original licence link has changed is not relivant.
45062 * <script type="text/javascript">
45066 * @class Roo.form.Layout
45067 * @extends Roo.Component
45068 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45070 * @param {Object} config Configuration options
45072 Roo.form.Layout = function(config){
45074 if (config.items) {
45075 xitems = config.items;
45076 delete config.items;
45078 Roo.form.Layout.superclass.constructor.call(this, config);
45080 Roo.each(xitems, this.addxtype, this);
45084 Roo.extend(Roo.form.Layout, Roo.Component, {
45086 * @cfg {String/Object} autoCreate
45087 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
45090 * @cfg {String/Object/Function} style
45091 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
45092 * a function which returns such a specification.
45095 * @cfg {String} labelAlign
45096 * Valid values are "left," "top" and "right" (defaults to "left")
45099 * @cfg {Number} labelWidth
45100 * Fixed width in pixels of all field labels (defaults to undefined)
45103 * @cfg {Boolean} clear
45104 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
45108 * @cfg {String} labelSeparator
45109 * The separator to use after field labels (defaults to ':')
45111 labelSeparator : ':',
45113 * @cfg {Boolean} hideLabels
45114 * True to suppress the display of field labels in this layout (defaults to false)
45116 hideLabels : false,
45119 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
45124 onRender : function(ct, position){
45125 if(this.el){ // from markup
45126 this.el = Roo.get(this.el);
45127 }else { // generate
45128 var cfg = this.getAutoCreate();
45129 this.el = ct.createChild(cfg, position);
45132 this.el.applyStyles(this.style);
45134 if(this.labelAlign){
45135 this.el.addClass('x-form-label-'+this.labelAlign);
45137 if(this.hideLabels){
45138 this.labelStyle = "display:none";
45139 this.elementStyle = "padding-left:0;";
45141 if(typeof this.labelWidth == 'number'){
45142 this.labelStyle = "width:"+this.labelWidth+"px;";
45143 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
45145 if(this.labelAlign == 'top'){
45146 this.labelStyle = "width:auto;";
45147 this.elementStyle = "padding-left:0;";
45150 var stack = this.stack;
45151 var slen = stack.length;
45153 if(!this.fieldTpl){
45154 var t = new Roo.Template(
45155 '<div class="x-form-item {5}">',
45156 '<label for="{0}" style="{2}">{1}{4}</label>',
45157 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45159 '</div><div class="x-form-clear-left"></div>'
45161 t.disableFormats = true;
45163 Roo.form.Layout.prototype.fieldTpl = t;
45165 for(var i = 0; i < slen; i++) {
45166 if(stack[i].isFormField){
45167 this.renderField(stack[i]);
45169 this.renderComponent(stack[i]);
45174 this.el.createChild({cls:'x-form-clear'});
45179 renderField : function(f){
45180 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
45183 f.labelStyle||this.labelStyle||'', //2
45184 this.elementStyle||'', //3
45185 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
45186 f.itemCls||this.itemCls||'' //5
45187 ], true).getPrevSibling());
45191 renderComponent : function(c){
45192 c.render(c.isLayout ? this.el : this.el.createChild());
45195 * Adds a object form elements (using the xtype property as the factory method.)
45196 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
45197 * @param {Object} config
45199 addxtype : function(o)
45201 // create the lement.
45202 o.form = this.form;
45203 var fe = Roo.factory(o, Roo.form);
45204 this.form.allItems.push(fe);
45205 this.stack.push(fe);
45207 if (fe.isFormField) {
45208 this.form.items.add(fe);
45216 * @class Roo.form.Column
45217 * @extends Roo.form.Layout
45218 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
45220 * @param {Object} config Configuration options
45222 Roo.form.Column = function(config){
45223 Roo.form.Column.superclass.constructor.call(this, config);
45226 Roo.extend(Roo.form.Column, Roo.form.Layout, {
45228 * @cfg {Number/String} width
45229 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45232 * @cfg {String/Object} autoCreate
45233 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
45237 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
45240 onRender : function(ct, position){
45241 Roo.form.Column.superclass.onRender.call(this, ct, position);
45243 this.el.setWidth(this.width);
45250 * @class Roo.form.Row
45251 * @extends Roo.form.Layout
45252 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
45254 * @param {Object} config Configuration options
45258 Roo.form.Row = function(config){
45259 Roo.form.Row.superclass.constructor.call(this, config);
45262 Roo.extend(Roo.form.Row, Roo.form.Layout, {
45264 * @cfg {Number/String} width
45265 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45268 * @cfg {Number/String} height
45269 * The fixed height of the column in pixels or CSS value (defaults to "auto")
45271 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
45275 onRender : function(ct, position){
45276 //console.log('row render');
45278 var t = new Roo.Template(
45279 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
45280 '<label for="{0}" style="{2}">{1}{4}</label>',
45281 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45285 t.disableFormats = true;
45287 Roo.form.Layout.prototype.rowTpl = t;
45289 this.fieldTpl = this.rowTpl;
45291 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
45292 var labelWidth = 100;
45294 if ((this.labelAlign != 'top')) {
45295 if (typeof this.labelWidth == 'number') {
45296 labelWidth = this.labelWidth
45298 this.padWidth = 20 + labelWidth;
45302 Roo.form.Column.superclass.onRender.call(this, ct, position);
45304 this.el.setWidth(this.width);
45307 this.el.setHeight(this.height);
45312 renderField : function(f){
45313 f.fieldEl = this.fieldTpl.append(this.el, [
45314 f.id, f.fieldLabel,
45315 f.labelStyle||this.labelStyle||'',
45316 this.elementStyle||'',
45317 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
45318 f.itemCls||this.itemCls||'',
45319 f.width ? f.width + this.padWidth : 160 + this.padWidth
45326 * @class Roo.form.FieldSet
45327 * @extends Roo.form.Layout
45328 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
45330 * @param {Object} config Configuration options
45332 Roo.form.FieldSet = function(config){
45333 Roo.form.FieldSet.superclass.constructor.call(this, config);
45336 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
45338 * @cfg {String} legend
45339 * The text to display as the legend for the FieldSet (defaults to '')
45342 * @cfg {String/Object} autoCreate
45343 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
45347 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
45350 onRender : function(ct, position){
45351 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
45353 this.setLegend(this.legend);
45358 setLegend : function(text){
45360 this.el.child('legend').update(text);
45365 * Ext JS Library 1.1.1
45366 * Copyright(c) 2006-2007, Ext JS, LLC.
45368 * Originally Released Under LGPL - original licence link has changed is not relivant.
45371 * <script type="text/javascript">
45374 * @class Roo.form.VTypes
45375 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
45378 Roo.form.VTypes = function(){
45379 // closure these in so they are only created once.
45380 var alpha = /^[a-zA-Z_]+$/;
45381 var alphanum = /^[a-zA-Z0-9_]+$/;
45382 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
45383 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
45385 // All these messages and functions are configurable
45388 * The function used to validate email addresses
45389 * @param {String} value The email address
45391 'email' : function(v){
45392 return email.test(v);
45395 * The error text to display when the email validation function returns false
45398 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
45400 * The keystroke filter mask to be applied on email input
45403 'emailMask' : /[a-z0-9_\.\-@]/i,
45406 * The function used to validate URLs
45407 * @param {String} value The URL
45409 'url' : function(v){
45410 return url.test(v);
45413 * The error text to display when the url validation function returns false
45416 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
45419 * The function used to validate alpha values
45420 * @param {String} value The value
45422 'alpha' : function(v){
45423 return alpha.test(v);
45426 * The error text to display when the alpha validation function returns false
45429 'alphaText' : 'This field should only contain letters and _',
45431 * The keystroke filter mask to be applied on alpha input
45434 'alphaMask' : /[a-z_]/i,
45437 * The function used to validate alphanumeric values
45438 * @param {String} value The value
45440 'alphanum' : function(v){
45441 return alphanum.test(v);
45444 * The error text to display when the alphanumeric validation function returns false
45447 'alphanumText' : 'This field should only contain letters, numbers and _',
45449 * The keystroke filter mask to be applied on alphanumeric input
45452 'alphanumMask' : /[a-z0-9_]/i
45454 }();//<script type="text/javascript">
45457 * @class Roo.form.FCKeditor
45458 * @extends Roo.form.TextArea
45459 * Wrapper around the FCKEditor http://www.fckeditor.net
45461 * Creates a new FCKeditor
45462 * @param {Object} config Configuration options
45464 Roo.form.FCKeditor = function(config){
45465 Roo.form.FCKeditor.superclass.constructor.call(this, config);
45468 * @event editorinit
45469 * Fired when the editor is initialized - you can add extra handlers here..
45470 * @param {FCKeditor} this
45471 * @param {Object} the FCK object.
45478 Roo.form.FCKeditor.editors = { };
45479 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
45481 //defaultAutoCreate : {
45482 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
45486 * @cfg {Object} fck options - see fck manual for details.
45491 * @cfg {Object} fck toolbar set (Basic or Default)
45493 toolbarSet : 'Basic',
45495 * @cfg {Object} fck BasePath
45497 basePath : '/fckeditor/',
45505 onRender : function(ct, position)
45508 this.defaultAutoCreate = {
45510 style:"width:300px;height:60px;",
45511 autocomplete: "off"
45514 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
45517 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
45518 if(this.preventScrollbars){
45519 this.el.setStyle("overflow", "hidden");
45521 this.el.setHeight(this.growMin);
45524 //console.log('onrender' + this.getId() );
45525 Roo.form.FCKeditor.editors[this.getId()] = this;
45528 this.replaceTextarea() ;
45532 getEditor : function() {
45533 return this.fckEditor;
45536 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
45537 * @param {Mixed} value The value to set
45541 setValue : function(value)
45543 //console.log('setValue: ' + value);
45545 if(typeof(value) == 'undefined') { // not sure why this is happending...
45548 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
45550 //if(!this.el || !this.getEditor()) {
45551 // this.value = value;
45552 //this.setValue.defer(100,this,[value]);
45556 if(!this.getEditor()) {
45560 this.getEditor().SetData(value);
45567 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
45568 * @return {Mixed} value The field value
45570 getValue : function()
45573 if (this.frame && this.frame.dom.style.display == 'none') {
45574 return Roo.form.FCKeditor.superclass.getValue.call(this);
45577 if(!this.el || !this.getEditor()) {
45579 // this.getValue.defer(100,this);
45584 var value=this.getEditor().GetData();
45585 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
45586 return Roo.form.FCKeditor.superclass.getValue.call(this);
45592 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
45593 * @return {Mixed} value The field value
45595 getRawValue : function()
45597 if (this.frame && this.frame.dom.style.display == 'none') {
45598 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
45601 if(!this.el || !this.getEditor()) {
45602 //this.getRawValue.defer(100,this);
45609 var value=this.getEditor().GetData();
45610 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
45611 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
45615 setSize : function(w,h) {
45619 //if (this.frame && this.frame.dom.style.display == 'none') {
45620 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
45623 //if(!this.el || !this.getEditor()) {
45624 // this.setSize.defer(100,this, [w,h]);
45630 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
45632 this.frame.dom.setAttribute('width', w);
45633 this.frame.dom.setAttribute('height', h);
45634 this.frame.setSize(w,h);
45638 toggleSourceEdit : function(value) {
45642 this.el.dom.style.display = value ? '' : 'none';
45643 this.frame.dom.style.display = value ? 'none' : '';
45648 focus: function(tag)
45650 if (this.frame.dom.style.display == 'none') {
45651 return Roo.form.FCKeditor.superclass.focus.call(this);
45653 if(!this.el || !this.getEditor()) {
45654 this.focus.defer(100,this, [tag]);
45661 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
45662 this.getEditor().Focus();
45664 if (!this.getEditor().Selection.GetSelection()) {
45665 this.focus.defer(100,this, [tag]);
45670 var r = this.getEditor().EditorDocument.createRange();
45671 r.setStart(tgs[0],0);
45672 r.setEnd(tgs[0],0);
45673 this.getEditor().Selection.GetSelection().removeAllRanges();
45674 this.getEditor().Selection.GetSelection().addRange(r);
45675 this.getEditor().Focus();
45682 replaceTextarea : function()
45684 if ( document.getElementById( this.getId() + '___Frame' ) )
45686 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
45688 // We must check the elements firstly using the Id and then the name.
45689 var oTextarea = document.getElementById( this.getId() );
45691 var colElementsByName = document.getElementsByName( this.getId() ) ;
45693 oTextarea.style.display = 'none' ;
45695 if ( oTextarea.tabIndex ) {
45696 this.TabIndex = oTextarea.tabIndex ;
45699 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
45700 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
45701 this.frame = Roo.get(this.getId() + '___Frame')
45704 _getConfigHtml : function()
45708 for ( var o in this.fckconfig ) {
45709 sConfig += sConfig.length > 0 ? '&' : '';
45710 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
45713 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
45717 _getIFrameHtml : function()
45719 var sFile = 'fckeditor.html' ;
45720 /* no idea what this is about..
45723 if ( (/fcksource=true/i).test( window.top.location.search ) )
45724 sFile = 'fckeditor.original.html' ;
45729 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
45730 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
45733 var html = '<iframe id="' + this.getId() +
45734 '___Frame" src="' + sLink +
45735 '" width="' + this.width +
45736 '" height="' + this.height + '"' +
45737 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
45738 ' frameborder="0" scrolling="no"></iframe>' ;
45743 _insertHtmlBefore : function( html, element )
45745 if ( element.insertAdjacentHTML ) {
45747 element.insertAdjacentHTML( 'beforeBegin', html ) ;
45749 var oRange = document.createRange() ;
45750 oRange.setStartBefore( element ) ;
45751 var oFragment = oRange.createContextualFragment( html );
45752 element.parentNode.insertBefore( oFragment, element ) ;
45765 //Roo.reg('fckeditor', Roo.form.FCKeditor);
45767 function FCKeditor_OnComplete(editorInstance){
45768 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
45769 f.fckEditor = editorInstance;
45770 //console.log("loaded");
45771 f.fireEvent('editorinit', f, editorInstance);
45791 //<script type="text/javascript">
45793 * @class Roo.form.GridField
45794 * @extends Roo.form.Field
45795 * Embed a grid (or editable grid into a form)
45798 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
45800 * xgrid.store = Roo.data.Store
45801 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
45802 * xgrid.store.reader = Roo.data.JsonReader
45806 * Creates a new GridField
45807 * @param {Object} config Configuration options
45809 Roo.form.GridField = function(config){
45810 Roo.form.GridField.superclass.constructor.call(this, config);
45814 Roo.extend(Roo.form.GridField, Roo.form.Field, {
45816 * @cfg {Number} width - used to restrict width of grid..
45820 * @cfg {Number} height - used to restrict height of grid..
45824 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
45830 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45831 * {tag: "input", type: "checkbox", autocomplete: "off"})
45833 // defaultAutoCreate : { tag: 'div' },
45834 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45836 * @cfg {String} addTitle Text to include for adding a title.
45840 onResize : function(){
45841 Roo.form.Field.superclass.onResize.apply(this, arguments);
45844 initEvents : function(){
45845 // Roo.form.Checkbox.superclass.initEvents.call(this);
45846 // has no events...
45851 getResizeEl : function(){
45855 getPositionEl : function(){
45860 onRender : function(ct, position){
45862 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
45863 var style = this.style;
45866 Roo.form.GridField.superclass.onRender.call(this, ct, position);
45867 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
45868 this.viewEl = this.wrap.createChild({ tag: 'div' });
45870 this.viewEl.applyStyles(style);
45873 this.viewEl.setWidth(this.width);
45876 this.viewEl.setHeight(this.height);
45878 //if(this.inputValue !== undefined){
45879 //this.setValue(this.value);
45882 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
45885 this.grid.render();
45886 this.grid.getDataSource().on('remove', this.refreshValue, this);
45887 this.grid.getDataSource().on('update', this.refreshValue, this);
45888 this.grid.on('afteredit', this.refreshValue, this);
45894 * Sets the value of the item.
45895 * @param {String} either an object or a string..
45897 setValue : function(v){
45899 v = v || []; // empty set..
45900 // this does not seem smart - it really only affects memoryproxy grids..
45901 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
45902 var ds = this.grid.getDataSource();
45903 // assumes a json reader..
45905 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
45906 ds.loadData( data);
45908 // clear selection so it does not get stale.
45909 if (this.grid.sm) {
45910 this.grid.sm.clearSelections();
45913 Roo.form.GridField.superclass.setValue.call(this, v);
45914 this.refreshValue();
45915 // should load data in the grid really....
45919 refreshValue: function() {
45921 this.grid.getDataSource().each(function(r) {
45924 this.el.dom.value = Roo.encode(val);
45932 * Ext JS Library 1.1.1
45933 * Copyright(c) 2006-2007, Ext JS, LLC.
45935 * Originally Released Under LGPL - original licence link has changed is not relivant.
45938 * <script type="text/javascript">
45941 * @class Roo.form.DisplayField
45942 * @extends Roo.form.Field
45943 * A generic Field to display non-editable data.
45945 * Creates a new Display Field item.
45946 * @param {Object} config Configuration options
45948 Roo.form.DisplayField = function(config){
45949 Roo.form.DisplayField.superclass.constructor.call(this, config);
45953 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
45954 inputType: 'hidden',
45960 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45962 focusClass : undefined,
45964 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45966 fieldClass: 'x-form-field',
45969 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
45971 valueRenderer: undefined,
45975 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45976 * {tag: "input", type: "checkbox", autocomplete: "off"})
45979 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45981 onResize : function(){
45982 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
45986 initEvents : function(){
45987 // Roo.form.Checkbox.superclass.initEvents.call(this);
45988 // has no events...
45993 getResizeEl : function(){
45997 getPositionEl : function(){
46002 onRender : function(ct, position){
46004 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
46005 //if(this.inputValue !== undefined){
46006 this.wrap = this.el.wrap();
46008 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
46010 if (this.bodyStyle) {
46011 this.viewEl.applyStyles(this.bodyStyle);
46013 //this.viewEl.setStyle('padding', '2px');
46015 this.setValue(this.value);
46020 initValue : Roo.emptyFn,
46025 onClick : function(){
46030 * Sets the checked state of the checkbox.
46031 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
46033 setValue : function(v){
46035 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
46036 // this might be called before we have a dom element..
46037 if (!this.viewEl) {
46040 this.viewEl.dom.innerHTML = html;
46041 Roo.form.DisplayField.superclass.setValue.call(this, v);
46051 * @class Roo.form.DayPicker
46052 * @extends Roo.form.Field
46053 * A Day picker show [M] [T] [W] ....
46055 * Creates a new Day Picker
46056 * @param {Object} config Configuration options
46058 Roo.form.DayPicker= function(config){
46059 Roo.form.DayPicker.superclass.constructor.call(this, config);
46063 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
46065 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46067 focusClass : undefined,
46069 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46071 fieldClass: "x-form-field",
46074 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46075 * {tag: "input", type: "checkbox", autocomplete: "off"})
46077 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
46080 actionMode : 'viewEl',
46084 inputType : 'hidden',
46087 inputElement: false, // real input element?
46088 basedOn: false, // ????
46090 isFormField: true, // not sure where this is needed!!!!
46092 onResize : function(){
46093 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
46094 if(!this.boxLabel){
46095 this.el.alignTo(this.wrap, 'c-c');
46099 initEvents : function(){
46100 Roo.form.Checkbox.superclass.initEvents.call(this);
46101 this.el.on("click", this.onClick, this);
46102 this.el.on("change", this.onClick, this);
46106 getResizeEl : function(){
46110 getPositionEl : function(){
46116 onRender : function(ct, position){
46117 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
46119 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
46121 var r1 = '<table><tr>';
46122 var r2 = '<tr class="x-form-daypick-icons">';
46123 for (var i=0; i < 7; i++) {
46124 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
46125 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
46128 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
46129 viewEl.select('img').on('click', this.onClick, this);
46130 this.viewEl = viewEl;
46133 // this will not work on Chrome!!!
46134 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
46135 this.el.on('propertychange', this.setFromHidden, this); //ie
46143 initValue : Roo.emptyFn,
46146 * Returns the checked state of the checkbox.
46147 * @return {Boolean} True if checked, else false
46149 getValue : function(){
46150 return this.el.dom.value;
46155 onClick : function(e){
46156 //this.setChecked(!this.checked);
46157 Roo.get(e.target).toggleClass('x-menu-item-checked');
46158 this.refreshValue();
46159 //if(this.el.dom.checked != this.checked){
46160 // this.setValue(this.el.dom.checked);
46165 refreshValue : function()
46168 this.viewEl.select('img',true).each(function(e,i,n) {
46169 val += e.is(".x-menu-item-checked") ? String(n) : '';
46171 this.setValue(val, true);
46175 * Sets the checked state of the checkbox.
46176 * On is always based on a string comparison between inputValue and the param.
46177 * @param {Boolean/String} value - the value to set
46178 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
46180 setValue : function(v,suppressEvent){
46181 if (!this.el.dom) {
46184 var old = this.el.dom.value ;
46185 this.el.dom.value = v;
46186 if (suppressEvent) {
46190 // update display..
46191 this.viewEl.select('img',true).each(function(e,i,n) {
46193 var on = e.is(".x-menu-item-checked");
46194 var newv = v.indexOf(String(n)) > -1;
46196 e.toggleClass('x-menu-item-checked');
46202 this.fireEvent('change', this, v, old);
46207 // handle setting of hidden value by some other method!!?!?
46208 setFromHidden: function()
46213 //console.log("SET FROM HIDDEN");
46214 //alert('setFrom hidden');
46215 this.setValue(this.el.dom.value);
46218 onDestroy : function()
46221 Roo.get(this.viewEl).remove();
46224 Roo.form.DayPicker.superclass.onDestroy.call(this);
46228 * RooJS Library 1.1.1
46229 * Copyright(c) 2008-2011 Alan Knowles
46236 * @class Roo.form.ComboCheck
46237 * @extends Roo.form.ComboBox
46238 * A combobox for multiple select items.
46240 * FIXME - could do with a reset button..
46243 * Create a new ComboCheck
46244 * @param {Object} config Configuration options
46246 Roo.form.ComboCheck = function(config){
46247 Roo.form.ComboCheck.superclass.constructor.call(this, config);
46248 // should verify some data...
46250 // hiddenName = required..
46251 // displayField = required
46252 // valudField == required
46253 var req= [ 'hiddenName', 'displayField', 'valueField' ];
46255 Roo.each(req, function(e) {
46256 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
46257 throw "Roo.form.ComboCheck : missing value for: " + e;
46264 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
46269 selectedClass: 'x-menu-item-checked',
46272 onRender : function(ct, position){
46278 var cls = 'x-combo-list';
46281 this.tpl = new Roo.Template({
46282 html : '<div class="'+cls+'-item x-menu-check-item">' +
46283 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
46284 '<span>{' + this.displayField + '}</span>' +
46291 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
46292 this.view.singleSelect = false;
46293 this.view.multiSelect = true;
46294 this.view.toggleSelect = true;
46295 this.pageTb.add(new Roo.Toolbar.Fill(), {
46298 handler: function()
46305 onViewOver : function(e, t){
46311 onViewClick : function(doFocus,index){
46315 select: function () {
46316 //Roo.log("SELECT CALLED");
46319 selectByValue : function(xv, scrollIntoView){
46320 var ar = this.getValueArray();
46323 Roo.each(ar, function(v) {
46324 if(v === undefined || v === null){
46327 var r = this.findRecord(this.valueField, v);
46329 sels.push(this.store.indexOf(r))
46333 this.view.select(sels);
46339 onSelect : function(record, index){
46340 // Roo.log("onselect Called");
46341 // this is only called by the clear button now..
46342 this.view.clearSelections();
46343 this.setValue('[]');
46344 if (this.value != this.valueBefore) {
46345 this.fireEvent('change', this, this.value, this.valueBefore);
46346 this.valueBefore = this.value;
46349 getValueArray : function()
46354 //Roo.log(this.value);
46355 if (typeof(this.value) == 'undefined') {
46358 var ar = Roo.decode(this.value);
46359 return ar instanceof Array ? ar : []; //?? valid?
46362 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
46367 expand : function ()
46370 Roo.form.ComboCheck.superclass.expand.call(this);
46371 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
46372 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
46377 collapse : function(){
46378 Roo.form.ComboCheck.superclass.collapse.call(this);
46379 var sl = this.view.getSelectedIndexes();
46380 var st = this.store;
46384 Roo.each(sl, function(i) {
46386 nv.push(r.get(this.valueField));
46388 this.setValue(Roo.encode(nv));
46389 if (this.value != this.valueBefore) {
46391 this.fireEvent('change', this, this.value, this.valueBefore);
46392 this.valueBefore = this.value;
46397 setValue : function(v){
46401 var vals = this.getValueArray();
46403 Roo.each(vals, function(k) {
46404 var r = this.findRecord(this.valueField, k);
46406 tv.push(r.data[this.displayField]);
46407 }else if(this.valueNotFoundText !== undefined){
46408 tv.push( this.valueNotFoundText );
46413 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
46414 this.hiddenField.value = v;
46420 * Ext JS Library 1.1.1
46421 * Copyright(c) 2006-2007, Ext JS, LLC.
46423 * Originally Released Under LGPL - original licence link has changed is not relivant.
46426 * <script type="text/javascript">
46430 * @class Roo.form.Signature
46431 * @extends Roo.form.Field
46435 * @param {Object} config Configuration options
46438 Roo.form.Signature = function(config){
46439 Roo.form.Signature.superclass.constructor.call(this, config);
46441 this.addEvents({// not in used??
46444 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
46445 * @param {Roo.form.Signature} combo This combo box
46450 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
46451 * @param {Roo.form.ComboBox} combo This combo box
46452 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
46458 Roo.extend(Roo.form.Signature, Roo.form.Field, {
46460 * @cfg {Object} labels Label to use when rendering a form.
46464 * confirm : "Confirm"
46469 confirm : "Confirm"
46472 * @cfg {Number} width The signature panel width (defaults to 300)
46476 * @cfg {Number} height The signature panel height (defaults to 100)
46480 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
46482 allowBlank : false,
46485 // {Object} signPanel The signature SVG panel element (defaults to {})
46487 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
46488 isMouseDown : false,
46489 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
46490 isConfirmed : false,
46491 // {String} signatureTmp SVG mapping string (defaults to empty string)
46495 defaultAutoCreate : { // modified by initCompnoent..
46501 onRender : function(ct, position){
46503 Roo.form.Signature.superclass.onRender.call(this, ct, position);
46505 this.wrap = this.el.wrap({
46506 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
46509 this.createToolbar(this);
46510 this.signPanel = this.wrap.createChild({
46512 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
46516 this.svgID = Roo.id();
46517 this.svgEl = this.signPanel.createChild({
46518 xmlns : 'http://www.w3.org/2000/svg',
46520 id : this.svgID + "-svg",
46522 height: this.height,
46523 viewBox: '0 0 '+this.width+' '+this.height,
46527 id: this.svgID + "-svg-r",
46529 height: this.height,
46534 id: this.svgID + "-svg-l",
46536 y1: (this.height*0.8), // start set the line in 80% of height
46537 x2: this.width, // end
46538 y2: (this.height*0.8), // end set the line in 80% of height
46540 'stroke-width': "1",
46541 'stroke-dasharray': "3",
46542 'shape-rendering': "crispEdges",
46543 'pointer-events': "none"
46547 id: this.svgID + "-svg-p",
46549 'stroke-width': "3",
46551 'pointer-events': 'none'
46556 this.svgBox = this.svgEl.dom.getScreenCTM();
46558 createSVG : function(){
46559 var svg = this.signPanel;
46560 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
46563 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
46564 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
46565 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
46566 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
46567 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
46568 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
46569 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
46572 isTouchEvent : function(e){
46573 return e.type.match(/^touch/);
46575 getCoords : function (e) {
46576 var pt = this.svgEl.dom.createSVGPoint();
46579 if (this.isTouchEvent(e)) {
46580 pt.x = e.targetTouches[0].clientX
46581 pt.y = e.targetTouches[0].clientY;
46583 var a = this.svgEl.dom.getScreenCTM();
46584 var b = a.inverse();
46585 var mx = pt.matrixTransform(b);
46586 return mx.x + ',' + mx.y;
46588 //mouse event headler
46589 down : function (e) {
46590 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
46591 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
46593 this.isMouseDown = true;
46595 e.preventDefault();
46597 move : function (e) {
46598 if (this.isMouseDown) {
46599 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
46600 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
46603 e.preventDefault();
46605 up : function (e) {
46606 this.isMouseDown = false;
46607 var sp = this.signatureTmp.split(' ');
46610 if(!sp[sp.length-2].match(/^L/)){
46614 this.signatureTmp = sp.join(" ");
46617 if(this.getValue() != this.signatureTmp){
46618 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46619 this.isConfirmed = false;
46621 e.preventDefault();
46625 * Protected method that will not generally be called directly. It
46626 * is called when the editor creates its toolbar. Override this method if you need to
46627 * add custom toolbar buttons.
46628 * @param {HtmlEditor} editor
46630 createToolbar : function(editor){
46631 function btn(id, toggle, handler){
46632 var xid = fid + '-'+ id ;
46636 cls : 'x-btn-icon x-edit-'+id,
46637 enableToggle:toggle !== false,
46638 scope: editor, // was editor...
46639 handler:handler||editor.relayBtnCmd,
46640 clickEvent:'mousedown',
46641 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46647 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46651 cls : ' x-signature-btn x-signature-'+id,
46652 scope: editor, // was editor...
46653 handler: this.reset,
46654 clickEvent:'mousedown',
46655 text: this.labels.clear
46662 cls : ' x-signature-btn x-signature-'+id,
46663 scope: editor, // was editor...
46664 handler: this.confirmHandler,
46665 clickEvent:'mousedown',
46666 text: this.labels.confirm
46673 * when user is clicked confirm then show this image.....
46675 * @return {String} Image Data URI
46677 getImageDataURI : function(){
46678 var svg = this.svgEl.dom.parentNode.innerHTML;
46679 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
46684 * @return {Boolean} this.isConfirmed
46686 getConfirmed : function(){
46687 return this.isConfirmed;
46691 * @return {Number} this.width
46693 getWidth : function(){
46698 * @return {Number} this.height
46700 getHeight : function(){
46701 return this.height;
46704 getSignature : function(){
46705 return this.signatureTmp;
46708 reset : function(){
46709 this.signatureTmp = '';
46710 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46711 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
46712 this.isConfirmed = false;
46713 Roo.form.Signature.superclass.reset.call(this);
46715 setSignature : function(s){
46716 this.signatureTmp = s;
46717 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46718 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
46720 this.isConfirmed = false;
46721 Roo.form.Signature.superclass.reset.call(this);
46724 // Roo.log(this.signPanel.dom.contentWindow.up())
46727 setConfirmed : function(){
46731 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
46734 confirmHandler : function(){
46735 if(!this.getSignature()){
46739 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
46740 this.setValue(this.getSignature());
46741 this.isConfirmed = true;
46743 this.fireEvent('confirm', this);
46746 // Subclasses should provide the validation implementation by overriding this
46747 validateValue : function(value){
46748 if(this.allowBlank){
46752 if(this.isConfirmed){
46759 * Ext JS Library 1.1.1
46760 * Copyright(c) 2006-2007, Ext JS, LLC.
46762 * Originally Released Under LGPL - original licence link has changed is not relivant.
46765 * <script type="text/javascript">
46770 * @class Roo.form.ComboBox
46771 * @extends Roo.form.TriggerField
46772 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
46774 * Create a new ComboBox.
46775 * @param {Object} config Configuration options
46777 Roo.form.Select = function(config){
46778 Roo.form.Select.superclass.constructor.call(this, config);
46782 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
46784 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
46787 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
46788 * rendering into an Roo.Editor, defaults to false)
46791 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
46792 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
46795 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
46798 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
46799 * the dropdown list (defaults to undefined, with no header element)
46803 * @cfg {String/Roo.Template} tpl The template to use to render the output
46807 defaultAutoCreate : {tag: "select" },
46809 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
46811 listWidth: undefined,
46813 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
46814 * mode = 'remote' or 'text' if mode = 'local')
46816 displayField: undefined,
46818 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
46819 * mode = 'remote' or 'value' if mode = 'local').
46820 * Note: use of a valueField requires the user make a selection
46821 * in order for a value to be mapped.
46823 valueField: undefined,
46827 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
46828 * field's data value (defaults to the underlying DOM element's name)
46830 hiddenName: undefined,
46832 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
46836 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
46838 selectedClass: 'x-combo-selected',
46840 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
46841 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
46842 * which displays a downward arrow icon).
46844 triggerClass : 'x-form-arrow-trigger',
46846 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
46850 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
46851 * anchor positions (defaults to 'tl-bl')
46853 listAlign: 'tl-bl?',
46855 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
46859 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
46860 * query specified by the allQuery config option (defaults to 'query')
46862 triggerAction: 'query',
46864 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
46865 * (defaults to 4, does not apply if editable = false)
46869 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
46870 * delay (typeAheadDelay) if it matches a known value (defaults to false)
46874 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
46875 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
46879 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
46880 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
46884 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
46885 * when editable = true (defaults to false)
46887 selectOnFocus:false,
46889 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
46891 queryParam: 'query',
46893 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
46894 * when mode = 'remote' (defaults to 'Loading...')
46896 loadingText: 'Loading...',
46898 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
46902 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
46906 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
46907 * traditional select (defaults to true)
46911 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
46915 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
46919 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
46920 * listWidth has a higher value)
46924 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
46925 * allow the user to set arbitrary text into the field (defaults to false)
46927 forceSelection:false,
46929 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
46930 * if typeAhead = true (defaults to 250)
46932 typeAheadDelay : 250,
46934 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
46935 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
46937 valueNotFoundText : undefined,
46940 * @cfg {String} defaultValue The value displayed after loading the store.
46945 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
46947 blockFocus : false,
46950 * @cfg {Boolean} disableClear Disable showing of clear button.
46952 disableClear : false,
46954 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
46956 alwaysQuery : false,
46962 // element that contains real text value.. (when hidden is used..)
46965 onRender : function(ct, position){
46966 Roo.form.Field.prototype.onRender.call(this, ct, position);
46969 this.store.on('beforeload', this.onBeforeLoad, this);
46970 this.store.on('load', this.onLoad, this);
46971 this.store.on('loadexception', this.onLoadException, this);
46972 this.store.load({});
46980 initEvents : function(){
46981 //Roo.form.ComboBox.superclass.initEvents.call(this);
46985 onDestroy : function(){
46988 this.store.un('beforeload', this.onBeforeLoad, this);
46989 this.store.un('load', this.onLoad, this);
46990 this.store.un('loadexception', this.onLoadException, this);
46992 //Roo.form.ComboBox.superclass.onDestroy.call(this);
46996 fireKey : function(e){
46997 if(e.isNavKeyPress() && !this.list.isVisible()){
46998 this.fireEvent("specialkey", this, e);
47003 onResize: function(w, h){
47011 * Allow or prevent the user from directly editing the field text. If false is passed,
47012 * the user will only be able to select from the items defined in the dropdown list. This method
47013 * is the runtime equivalent of setting the 'editable' config option at config time.
47014 * @param {Boolean} value True to allow the user to directly edit the field text
47016 setEditable : function(value){
47021 onBeforeLoad : function(){
47023 Roo.log("Select before load");
47026 this.innerList.update(this.loadingText ?
47027 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
47028 //this.restrictHeight();
47029 this.selectedIndex = -1;
47033 onLoad : function(){
47036 var dom = this.el.dom;
47037 dom.innerHTML = '';
47038 var od = dom.ownerDocument;
47040 if (this.emptyText) {
47041 var op = od.createElement('option');
47042 op.setAttribute('value', '');
47043 op.innerHTML = String.format('{0}', this.emptyText);
47044 dom.appendChild(op);
47046 if(this.store.getCount() > 0){
47048 var vf = this.valueField;
47049 var df = this.displayField;
47050 this.store.data.each(function(r) {
47051 // which colmsn to use... testing - cdoe / title..
47052 var op = od.createElement('option');
47053 op.setAttribute('value', r.data[vf]);
47054 op.innerHTML = String.format('{0}', r.data[df]);
47055 dom.appendChild(op);
47057 if (typeof(this.defaultValue != 'undefined')) {
47058 this.setValue(this.defaultValue);
47063 //this.onEmptyResults();
47068 onLoadException : function()
47070 dom.innerHTML = '';
47072 Roo.log("Select on load exception");
47076 Roo.log(this.store.reader.jsonData);
47077 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
47078 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
47084 onTypeAhead : function(){
47089 onSelect : function(record, index){
47090 Roo.log('on select?');
47092 if(this.fireEvent('beforeselect', this, record, index) !== false){
47093 this.setFromData(index > -1 ? record.data : false);
47095 this.fireEvent('select', this, record, index);
47100 * Returns the currently selected field value or empty string if no value is set.
47101 * @return {String} value The selected value
47103 getValue : function(){
47104 var dom = this.el.dom;
47105 this.value = dom.options[dom.selectedIndex].value;
47111 * Clears any text/value currently set in the field
47113 clearValue : function(){
47115 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
47120 * Sets the specified value into the field. If the value finds a match, the corresponding record text
47121 * will be displayed in the field. If the value does not match the data value of an existing item,
47122 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
47123 * Otherwise the field will be blank (although the value will still be set).
47124 * @param {String} value The value to match
47126 setValue : function(v){
47127 var d = this.el.dom;
47128 for (var i =0; i < d.options.length;i++) {
47129 if (v == d.options[i].value) {
47130 d.selectedIndex = i;
47138 * @property {Object} the last set data for the element
47143 * Sets the value of the field based on a object which is related to the record format for the store.
47144 * @param {Object} value the value to set as. or false on reset?
47146 setFromData : function(o){
47147 Roo.log('setfrom data?');
47153 reset : function(){
47157 findRecord : function(prop, value){
47162 if(this.store.getCount() > 0){
47163 this.store.each(function(r){
47164 if(r.data[prop] == value){
47174 getName: function()
47176 // returns hidden if it's set..
47177 if (!this.rendered) {return ''};
47178 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
47186 onEmptyResults : function(){
47187 Roo.log('empty results');
47192 * Returns true if the dropdown list is expanded, else false.
47194 isExpanded : function(){
47199 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
47200 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47201 * @param {String} value The data value of the item to select
47202 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47203 * selected item if it is not currently in view (defaults to true)
47204 * @return {Boolean} True if the value matched an item in the list, else false
47206 selectByValue : function(v, scrollIntoView){
47207 Roo.log('select By Value');
47210 if(v !== undefined && v !== null){
47211 var r = this.findRecord(this.valueField || this.displayField, v);
47213 this.select(this.store.indexOf(r), scrollIntoView);
47221 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
47222 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47223 * @param {Number} index The zero-based index of the list item to select
47224 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47225 * selected item if it is not currently in view (defaults to true)
47227 select : function(index, scrollIntoView){
47228 Roo.log('select ');
47231 this.selectedIndex = index;
47232 this.view.select(index);
47233 if(scrollIntoView !== false){
47234 var el = this.view.getNode(index);
47236 this.innerList.scrollChildIntoView(el, false);
47244 validateBlur : function(){
47251 initQuery : function(){
47252 this.doQuery(this.getRawValue());
47256 doForce : function(){
47257 if(this.el.dom.value.length > 0){
47258 this.el.dom.value =
47259 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
47265 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
47266 * query allowing the query action to be canceled if needed.
47267 * @param {String} query The SQL query to execute
47268 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
47269 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
47270 * saved in the current store (defaults to false)
47272 doQuery : function(q, forceAll){
47274 Roo.log('doQuery?');
47275 if(q === undefined || q === null){
47280 forceAll: forceAll,
47284 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
47288 forceAll = qe.forceAll;
47289 if(forceAll === true || (q.length >= this.minChars)){
47290 if(this.lastQuery != q || this.alwaysQuery){
47291 this.lastQuery = q;
47292 if(this.mode == 'local'){
47293 this.selectedIndex = -1;
47295 this.store.clearFilter();
47297 this.store.filter(this.displayField, q);
47301 this.store.baseParams[this.queryParam] = q;
47303 params: this.getParams(q)
47308 this.selectedIndex = -1;
47315 getParams : function(q){
47317 //p[this.queryParam] = q;
47320 p.limit = this.pageSize;
47326 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
47328 collapse : function(){
47333 collapseIf : function(e){
47338 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
47340 expand : function(){
47348 * @cfg {Boolean} grow
47352 * @cfg {Number} growMin
47356 * @cfg {Number} growMax
47364 setWidth : function()
47368 getResizeEl : function(){
47371 });//<script type="text/javasscript">
47375 * @class Roo.DDView
47376 * A DnD enabled version of Roo.View.
47377 * @param {Element/String} container The Element in which to create the View.
47378 * @param {String} tpl The template string used to create the markup for each element of the View
47379 * @param {Object} config The configuration properties. These include all the config options of
47380 * {@link Roo.View} plus some specific to this class.<br>
47382 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
47383 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
47385 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
47386 .x-view-drag-insert-above {
47387 border-top:1px dotted #3366cc;
47389 .x-view-drag-insert-below {
47390 border-bottom:1px dotted #3366cc;
47396 Roo.DDView = function(container, tpl, config) {
47397 Roo.DDView.superclass.constructor.apply(this, arguments);
47398 this.getEl().setStyle("outline", "0px none");
47399 this.getEl().unselectable();
47400 if (this.dragGroup) {
47401 this.setDraggable(this.dragGroup.split(","));
47403 if (this.dropGroup) {
47404 this.setDroppable(this.dropGroup.split(","));
47406 if (this.deletable) {
47407 this.setDeletable();
47409 this.isDirtyFlag = false;
47415 Roo.extend(Roo.DDView, Roo.View, {
47416 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
47417 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
47418 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
47419 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
47423 reset: Roo.emptyFn,
47425 clearInvalid: Roo.form.Field.prototype.clearInvalid,
47427 validate: function() {
47431 destroy: function() {
47432 this.purgeListeners();
47433 this.getEl.removeAllListeners();
47434 this.getEl().remove();
47435 if (this.dragZone) {
47436 if (this.dragZone.destroy) {
47437 this.dragZone.destroy();
47440 if (this.dropZone) {
47441 if (this.dropZone.destroy) {
47442 this.dropZone.destroy();
47447 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
47448 getName: function() {
47452 /** Loads the View from a JSON string representing the Records to put into the Store. */
47453 setValue: function(v) {
47455 throw "DDView.setValue(). DDView must be constructed with a valid Store";
47458 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
47459 this.store.proxy = new Roo.data.MemoryProxy(data);
47463 /** @return {String} a parenthesised list of the ids of the Records in the View. */
47464 getValue: function() {
47466 this.store.each(function(rec) {
47467 result += rec.id + ',';
47469 return result.substr(0, result.length - 1) + ')';
47472 getIds: function() {
47473 var i = 0, result = new Array(this.store.getCount());
47474 this.store.each(function(rec) {
47475 result[i++] = rec.id;
47480 isDirty: function() {
47481 return this.isDirtyFlag;
47485 * Part of the Roo.dd.DropZone interface. If no target node is found, the
47486 * whole Element becomes the target, and this causes the drop gesture to append.
47488 getTargetFromEvent : function(e) {
47489 var target = e.getTarget();
47490 while ((target !== null) && (target.parentNode != this.el.dom)) {
47491 target = target.parentNode;
47494 target = this.el.dom.lastChild || this.el.dom;
47500 * Create the drag data which consists of an object which has the property "ddel" as
47501 * the drag proxy element.
47503 getDragData : function(e) {
47504 var target = this.findItemFromChild(e.getTarget());
47506 this.handleSelection(e);
47507 var selNodes = this.getSelectedNodes();
47510 copy: this.copy || (this.allowCopy && e.ctrlKey),
47514 var selectedIndices = this.getSelectedIndexes();
47515 for (var i = 0; i < selectedIndices.length; i++) {
47516 dragData.records.push(this.store.getAt(selectedIndices[i]));
47518 if (selNodes.length == 1) {
47519 dragData.ddel = target.cloneNode(true); // the div element
47521 var div = document.createElement('div'); // create the multi element drag "ghost"
47522 div.className = 'multi-proxy';
47523 for (var i = 0, len = selNodes.length; i < len; i++) {
47524 div.appendChild(selNodes[i].cloneNode(true));
47526 dragData.ddel = div;
47528 //console.log(dragData)
47529 //console.log(dragData.ddel.innerHTML)
47532 //console.log('nodragData')
47536 /** Specify to which ddGroup items in this DDView may be dragged. */
47537 setDraggable: function(ddGroup) {
47538 if (ddGroup instanceof Array) {
47539 Roo.each(ddGroup, this.setDraggable, this);
47542 if (this.dragZone) {
47543 this.dragZone.addToGroup(ddGroup);
47545 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
47546 containerScroll: true,
47550 // Draggability implies selection. DragZone's mousedown selects the element.
47551 if (!this.multiSelect) { this.singleSelect = true; }
47553 // Wire the DragZone's handlers up to methods in *this*
47554 this.dragZone.getDragData = this.getDragData.createDelegate(this);
47558 /** Specify from which ddGroup this DDView accepts drops. */
47559 setDroppable: function(ddGroup) {
47560 if (ddGroup instanceof Array) {
47561 Roo.each(ddGroup, this.setDroppable, this);
47564 if (this.dropZone) {
47565 this.dropZone.addToGroup(ddGroup);
47567 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
47568 containerScroll: true,
47572 // Wire the DropZone's handlers up to methods in *this*
47573 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
47574 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
47575 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
47576 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
47577 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
47581 /** Decide whether to drop above or below a View node. */
47582 getDropPoint : function(e, n, dd){
47583 if (n == this.el.dom) { return "above"; }
47584 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
47585 var c = t + (b - t) / 2;
47586 var y = Roo.lib.Event.getPageY(e);
47594 onNodeEnter : function(n, dd, e, data){
47598 onNodeOver : function(n, dd, e, data){
47599 var pt = this.getDropPoint(e, n, dd);
47600 // set the insert point style on the target node
47601 var dragElClass = this.dropNotAllowed;
47604 if (pt == "above"){
47605 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
47606 targetElClass = "x-view-drag-insert-above";
47608 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
47609 targetElClass = "x-view-drag-insert-below";
47611 if (this.lastInsertClass != targetElClass){
47612 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
47613 this.lastInsertClass = targetElClass;
47616 return dragElClass;
47619 onNodeOut : function(n, dd, e, data){
47620 this.removeDropIndicators(n);
47623 onNodeDrop : function(n, dd, e, data){
47624 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
47627 var pt = this.getDropPoint(e, n, dd);
47628 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
47629 if (pt == "below") { insertAt++; }
47630 for (var i = 0; i < data.records.length; i++) {
47631 var r = data.records[i];
47632 var dup = this.store.getById(r.id);
47633 if (dup && (dd != this.dragZone)) {
47634 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
47637 this.store.insert(insertAt++, r.copy());
47639 data.source.isDirtyFlag = true;
47641 this.store.insert(insertAt++, r);
47643 this.isDirtyFlag = true;
47646 this.dragZone.cachedTarget = null;
47650 removeDropIndicators : function(n){
47652 Roo.fly(n).removeClass([
47653 "x-view-drag-insert-above",
47654 "x-view-drag-insert-below"]);
47655 this.lastInsertClass = "_noclass";
47660 * Utility method. Add a delete option to the DDView's context menu.
47661 * @param {String} imageUrl The URL of the "delete" icon image.
47663 setDeletable: function(imageUrl) {
47664 if (!this.singleSelect && !this.multiSelect) {
47665 this.singleSelect = true;
47667 var c = this.getContextMenu();
47668 this.contextMenu.on("itemclick", function(item) {
47671 this.remove(this.getSelectedIndexes());
47675 this.contextMenu.add({
47682 /** Return the context menu for this DDView. */
47683 getContextMenu: function() {
47684 if (!this.contextMenu) {
47685 // Create the View's context menu
47686 this.contextMenu = new Roo.menu.Menu({
47687 id: this.id + "-contextmenu"
47689 this.el.on("contextmenu", this.showContextMenu, this);
47691 return this.contextMenu;
47694 disableContextMenu: function() {
47695 if (this.contextMenu) {
47696 this.el.un("contextmenu", this.showContextMenu, this);
47700 showContextMenu: function(e, item) {
47701 item = this.findItemFromChild(e.getTarget());
47704 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
47705 this.contextMenu.showAt(e.getXY());
47710 * Remove {@link Roo.data.Record}s at the specified indices.
47711 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
47713 remove: function(selectedIndices) {
47714 selectedIndices = [].concat(selectedIndices);
47715 for (var i = 0; i < selectedIndices.length; i++) {
47716 var rec = this.store.getAt(selectedIndices[i]);
47717 this.store.remove(rec);
47722 * Double click fires the event, but also, if this is draggable, and there is only one other
47723 * related DropZone, it transfers the selected node.
47725 onDblClick : function(e){
47726 var item = this.findItemFromChild(e.getTarget());
47728 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
47731 if (this.dragGroup) {
47732 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
47733 while (targets.indexOf(this.dropZone) > -1) {
47734 targets.remove(this.dropZone);
47736 if (targets.length == 1) {
47737 this.dragZone.cachedTarget = null;
47738 var el = Roo.get(targets[0].getEl());
47739 var box = el.getBox(true);
47740 targets[0].onNodeDrop(el.dom, {
47742 xy: [box.x, box.y + box.height - 1]
47743 }, null, this.getDragData(e));
47749 handleSelection: function(e) {
47750 this.dragZone.cachedTarget = null;
47751 var item = this.findItemFromChild(e.getTarget());
47753 this.clearSelections(true);
47756 if (item && (this.multiSelect || this.singleSelect)){
47757 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
47758 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
47759 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
47760 this.unselect(item);
47762 this.select(item, this.multiSelect && e.ctrlKey);
47763 this.lastSelection = item;
47768 onItemClick : function(item, index, e){
47769 if(this.fireEvent("beforeclick", this, index, item, e) === false){
47775 unselect : function(nodeInfo, suppressEvent){
47776 var node = this.getNode(nodeInfo);
47777 if(node && this.isSelected(node)){
47778 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
47779 Roo.fly(node).removeClass(this.selectedClass);
47780 this.selections.remove(node);
47781 if(!suppressEvent){
47782 this.fireEvent("selectionchange", this, this.selections);
47790 * Ext JS Library 1.1.1
47791 * Copyright(c) 2006-2007, Ext JS, LLC.
47793 * Originally Released Under LGPL - original licence link has changed is not relivant.
47796 * <script type="text/javascript">
47800 * @class Roo.LayoutManager
47801 * @extends Roo.util.Observable
47802 * Base class for layout managers.
47804 Roo.LayoutManager = function(container, config){
47805 Roo.LayoutManager.superclass.constructor.call(this);
47806 this.el = Roo.get(container);
47807 // ie scrollbar fix
47808 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
47809 document.body.scroll = "no";
47810 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
47811 this.el.position('relative');
47813 this.id = this.el.id;
47814 this.el.addClass("x-layout-container");
47815 /** false to disable window resize monitoring @type Boolean */
47816 this.monitorWindowResize = true;
47821 * Fires when a layout is performed.
47822 * @param {Roo.LayoutManager} this
47826 * @event regionresized
47827 * Fires when the user resizes a region.
47828 * @param {Roo.LayoutRegion} region The resized region
47829 * @param {Number} newSize The new size (width for east/west, height for north/south)
47831 "regionresized" : true,
47833 * @event regioncollapsed
47834 * Fires when a region is collapsed.
47835 * @param {Roo.LayoutRegion} region The collapsed region
47837 "regioncollapsed" : true,
47839 * @event regionexpanded
47840 * Fires when a region is expanded.
47841 * @param {Roo.LayoutRegion} region The expanded region
47843 "regionexpanded" : true
47845 this.updating = false;
47846 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
47849 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
47851 * Returns true if this layout is currently being updated
47852 * @return {Boolean}
47854 isUpdating : function(){
47855 return this.updating;
47859 * Suspend the LayoutManager from doing auto-layouts while
47860 * making multiple add or remove calls
47862 beginUpdate : function(){
47863 this.updating = true;
47867 * Restore auto-layouts and optionally disable the manager from performing a layout
47868 * @param {Boolean} noLayout true to disable a layout update
47870 endUpdate : function(noLayout){
47871 this.updating = false;
47877 layout: function(){
47881 onRegionResized : function(region, newSize){
47882 this.fireEvent("regionresized", region, newSize);
47886 onRegionCollapsed : function(region){
47887 this.fireEvent("regioncollapsed", region);
47890 onRegionExpanded : function(region){
47891 this.fireEvent("regionexpanded", region);
47895 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
47896 * performs box-model adjustments.
47897 * @return {Object} The size as an object {width: (the width), height: (the height)}
47899 getViewSize : function(){
47901 if(this.el.dom != document.body){
47902 size = this.el.getSize();
47904 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
47906 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
47907 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
47912 * Returns the Element this layout is bound to.
47913 * @return {Roo.Element}
47915 getEl : function(){
47920 * Returns the specified region.
47921 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
47922 * @return {Roo.LayoutRegion}
47924 getRegion : function(target){
47925 return this.regions[target.toLowerCase()];
47928 onWindowResize : function(){
47929 if(this.monitorWindowResize){
47935 * Ext JS Library 1.1.1
47936 * Copyright(c) 2006-2007, Ext JS, LLC.
47938 * Originally Released Under LGPL - original licence link has changed is not relivant.
47941 * <script type="text/javascript">
47944 * @class Roo.BorderLayout
47945 * @extends Roo.LayoutManager
47946 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
47947 * please see: <br><br>
47948 * <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>
47949 * <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>
47952 var layout = new Roo.BorderLayout(document.body, {
47986 preferredTabWidth: 150
47991 var CP = Roo.ContentPanel;
47993 layout.beginUpdate();
47994 layout.add("north", new CP("north", "North"));
47995 layout.add("south", new CP("south", {title: "South", closable: true}));
47996 layout.add("west", new CP("west", {title: "West"}));
47997 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
47998 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
47999 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
48000 layout.getRegion("center").showPanel("center1");
48001 layout.endUpdate();
48004 <b>The container the layout is rendered into can be either the body element or any other element.
48005 If it is not the body element, the container needs to either be an absolute positioned element,
48006 or you will need to add "position:relative" to the css of the container. You will also need to specify
48007 the container size if it is not the body element.</b>
48010 * Create a new BorderLayout
48011 * @param {String/HTMLElement/Element} container The container this layout is bound to
48012 * @param {Object} config Configuration options
48014 Roo.BorderLayout = function(container, config){
48015 config = config || {};
48016 Roo.BorderLayout.superclass.constructor.call(this, container, config);
48017 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
48018 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
48019 var target = this.factory.validRegions[i];
48020 if(config[target]){
48021 this.addRegion(target, config[target]);
48026 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
48028 * Creates and adds a new region if it doesn't already exist.
48029 * @param {String} target The target region key (north, south, east, west or center).
48030 * @param {Object} config The regions config object
48031 * @return {BorderLayoutRegion} The new region
48033 addRegion : function(target, config){
48034 if(!this.regions[target]){
48035 var r = this.factory.create(target, this, config);
48036 this.bindRegion(target, r);
48038 return this.regions[target];
48042 bindRegion : function(name, r){
48043 this.regions[name] = r;
48044 r.on("visibilitychange", this.layout, this);
48045 r.on("paneladded", this.layout, this);
48046 r.on("panelremoved", this.layout, this);
48047 r.on("invalidated", this.layout, this);
48048 r.on("resized", this.onRegionResized, this);
48049 r.on("collapsed", this.onRegionCollapsed, this);
48050 r.on("expanded", this.onRegionExpanded, this);
48054 * Performs a layout update.
48056 layout : function(){
48057 if(this.updating) return;
48058 var size = this.getViewSize();
48059 var w = size.width;
48060 var h = size.height;
48065 //var x = 0, y = 0;
48067 var rs = this.regions;
48068 var north = rs["north"];
48069 var south = rs["south"];
48070 var west = rs["west"];
48071 var east = rs["east"];
48072 var center = rs["center"];
48073 //if(this.hideOnLayout){ // not supported anymore
48074 //c.el.setStyle("display", "none");
48076 if(north && north.isVisible()){
48077 var b = north.getBox();
48078 var m = north.getMargins();
48079 b.width = w - (m.left+m.right);
48082 centerY = b.height + b.y + m.bottom;
48083 centerH -= centerY;
48084 north.updateBox(this.safeBox(b));
48086 if(south && south.isVisible()){
48087 var b = south.getBox();
48088 var m = south.getMargins();
48089 b.width = w - (m.left+m.right);
48091 var totalHeight = (b.height + m.top + m.bottom);
48092 b.y = h - totalHeight + m.top;
48093 centerH -= totalHeight;
48094 south.updateBox(this.safeBox(b));
48096 if(west && west.isVisible()){
48097 var b = west.getBox();
48098 var m = west.getMargins();
48099 b.height = centerH - (m.top+m.bottom);
48101 b.y = centerY + m.top;
48102 var totalWidth = (b.width + m.left + m.right);
48103 centerX += totalWidth;
48104 centerW -= totalWidth;
48105 west.updateBox(this.safeBox(b));
48107 if(east && east.isVisible()){
48108 var b = east.getBox();
48109 var m = east.getMargins();
48110 b.height = centerH - (m.top+m.bottom);
48111 var totalWidth = (b.width + m.left + m.right);
48112 b.x = w - totalWidth + m.left;
48113 b.y = centerY + m.top;
48114 centerW -= totalWidth;
48115 east.updateBox(this.safeBox(b));
48118 var m = center.getMargins();
48120 x: centerX + m.left,
48121 y: centerY + m.top,
48122 width: centerW - (m.left+m.right),
48123 height: centerH - (m.top+m.bottom)
48125 //if(this.hideOnLayout){
48126 //center.el.setStyle("display", "block");
48128 center.updateBox(this.safeBox(centerBox));
48131 this.fireEvent("layout", this);
48135 safeBox : function(box){
48136 box.width = Math.max(0, box.width);
48137 box.height = Math.max(0, box.height);
48142 * Adds a ContentPanel (or subclass) to this layout.
48143 * @param {String} target The target region key (north, south, east, west or center).
48144 * @param {Roo.ContentPanel} panel The panel to add
48145 * @return {Roo.ContentPanel} The added panel
48147 add : function(target, panel){
48149 target = target.toLowerCase();
48150 return this.regions[target].add(panel);
48154 * Remove a ContentPanel (or subclass) to this layout.
48155 * @param {String} target The target region key (north, south, east, west or center).
48156 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
48157 * @return {Roo.ContentPanel} The removed panel
48159 remove : function(target, panel){
48160 target = target.toLowerCase();
48161 return this.regions[target].remove(panel);
48165 * Searches all regions for a panel with the specified id
48166 * @param {String} panelId
48167 * @return {Roo.ContentPanel} The panel or null if it wasn't found
48169 findPanel : function(panelId){
48170 var rs = this.regions;
48171 for(var target in rs){
48172 if(typeof rs[target] != "function"){
48173 var p = rs[target].getPanel(panelId);
48183 * Searches all regions for a panel with the specified id and activates (shows) it.
48184 * @param {String/ContentPanel} panelId The panels id or the panel itself
48185 * @return {Roo.ContentPanel} The shown panel or null
48187 showPanel : function(panelId) {
48188 var rs = this.regions;
48189 for(var target in rs){
48190 var r = rs[target];
48191 if(typeof r != "function"){
48192 if(r.hasPanel(panelId)){
48193 return r.showPanel(panelId);
48201 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
48202 * @param {Roo.state.Provider} provider (optional) An alternate state provider
48204 restoreState : function(provider){
48206 provider = Roo.state.Manager;
48208 var sm = new Roo.LayoutStateManager();
48209 sm.init(this, provider);
48213 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
48214 * object should contain properties for each region to add ContentPanels to, and each property's value should be
48215 * a valid ContentPanel config object. Example:
48217 // Create the main layout
48218 var layout = new Roo.BorderLayout('main-ct', {
48229 // Create and add multiple ContentPanels at once via configs
48232 id: 'source-files',
48234 title:'Ext Source Files',
48247 * @param {Object} regions An object containing ContentPanel configs by region name
48249 batchAdd : function(regions){
48250 this.beginUpdate();
48251 for(var rname in regions){
48252 var lr = this.regions[rname];
48254 this.addTypedPanels(lr, regions[rname]);
48261 addTypedPanels : function(lr, ps){
48262 if(typeof ps == 'string'){
48263 lr.add(new Roo.ContentPanel(ps));
48265 else if(ps instanceof Array){
48266 for(var i =0, len = ps.length; i < len; i++){
48267 this.addTypedPanels(lr, ps[i]);
48270 else if(!ps.events){ // raw config?
48272 delete ps.el; // prevent conflict
48273 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
48275 else { // panel object assumed!
48280 * Adds a xtype elements to the layout.
48284 xtype : 'ContentPanel',
48291 xtype : 'NestedLayoutPanel',
48297 items : [ ... list of content panels or nested layout panels.. ]
48301 * @param {Object} cfg Xtype definition of item to add.
48303 addxtype : function(cfg)
48305 // basically accepts a pannel...
48306 // can accept a layout region..!?!?
48307 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
48309 if (!cfg.xtype.match(/Panel$/)) {
48314 if (typeof(cfg.region) == 'undefined') {
48315 Roo.log("Failed to add Panel, region was not set");
48319 var region = cfg.region;
48325 xitems = cfg.items;
48332 case 'ContentPanel': // ContentPanel (el, cfg)
48333 case 'ScrollPanel': // ContentPanel (el, cfg)
48335 if(cfg.autoCreate) {
48336 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48338 var el = this.el.createChild();
48339 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
48342 this.add(region, ret);
48346 case 'TreePanel': // our new panel!
48347 cfg.el = this.el.createChild();
48348 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48349 this.add(region, ret);
48352 case 'NestedLayoutPanel':
48353 // create a new Layout (which is a Border Layout...
48354 var el = this.el.createChild();
48355 var clayout = cfg.layout;
48357 clayout.items = clayout.items || [];
48358 // replace this exitems with the clayout ones..
48359 xitems = clayout.items;
48362 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
48363 cfg.background = false;
48365 var layout = new Roo.BorderLayout(el, clayout);
48367 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
48368 //console.log('adding nested layout panel ' + cfg.toSource());
48369 this.add(region, ret);
48370 nb = {}; /// find first...
48375 // needs grid and region
48377 //var el = this.getRegion(region).el.createChild();
48378 var el = this.el.createChild();
48379 // create the grid first...
48381 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
48383 if (region == 'center' && this.active ) {
48384 cfg.background = false;
48386 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
48388 this.add(region, ret);
48389 if (cfg.background) {
48390 ret.on('activate', function(gp) {
48391 if (!gp.grid.rendered) {
48406 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
48408 // GridPanel (grid, cfg)
48411 this.beginUpdate();
48415 Roo.each(xitems, function(i) {
48416 region = nb && i.region ? i.region : false;
48418 var add = ret.addxtype(i);
48421 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
48422 if (!i.background) {
48423 abn[region] = nb[region] ;
48430 // make the last non-background panel active..
48431 //if (nb) { Roo.log(abn); }
48434 for(var r in abn) {
48435 region = this.getRegion(r);
48437 // tried using nb[r], but it does not work..
48439 region.showPanel(abn[r]);
48450 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
48451 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
48452 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
48453 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
48456 var CP = Roo.ContentPanel;
48458 var layout = Roo.BorderLayout.create({
48462 panels: [new CP("north", "North")]
48471 panels: [new CP("west", {title: "West"})]
48480 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
48489 panels: [new CP("south", {title: "South", closable: true})]
48496 preferredTabWidth: 150,
48498 new CP("center1", {title: "Close Me", closable: true}),
48499 new CP("center2", {title: "Center Panel", closable: false})
48504 layout.getRegion("center").showPanel("center1");
48509 Roo.BorderLayout.create = function(config, targetEl){
48510 var layout = new Roo.BorderLayout(targetEl || document.body, config);
48511 layout.beginUpdate();
48512 var regions = Roo.BorderLayout.RegionFactory.validRegions;
48513 for(var j = 0, jlen = regions.length; j < jlen; j++){
48514 var lr = regions[j];
48515 if(layout.regions[lr] && config[lr].panels){
48516 var r = layout.regions[lr];
48517 var ps = config[lr].panels;
48518 layout.addTypedPanels(r, ps);
48521 layout.endUpdate();
48526 Roo.BorderLayout.RegionFactory = {
48528 validRegions : ["north","south","east","west","center"],
48531 create : function(target, mgr, config){
48532 target = target.toLowerCase();
48533 if(config.lightweight || config.basic){
48534 return new Roo.BasicLayoutRegion(mgr, config, target);
48538 return new Roo.NorthLayoutRegion(mgr, config);
48540 return new Roo.SouthLayoutRegion(mgr, config);
48542 return new Roo.EastLayoutRegion(mgr, config);
48544 return new Roo.WestLayoutRegion(mgr, config);
48546 return new Roo.CenterLayoutRegion(mgr, config);
48548 throw 'Layout region "'+target+'" not supported.';
48552 * Ext JS Library 1.1.1
48553 * Copyright(c) 2006-2007, Ext JS, LLC.
48555 * Originally Released Under LGPL - original licence link has changed is not relivant.
48558 * <script type="text/javascript">
48562 * @class Roo.BasicLayoutRegion
48563 * @extends Roo.util.Observable
48564 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
48565 * and does not have a titlebar, tabs or any other features. All it does is size and position
48566 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
48568 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
48570 this.position = pos;
48573 * @scope Roo.BasicLayoutRegion
48577 * @event beforeremove
48578 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
48579 * @param {Roo.LayoutRegion} this
48580 * @param {Roo.ContentPanel} panel The panel
48581 * @param {Object} e The cancel event object
48583 "beforeremove" : true,
48585 * @event invalidated
48586 * Fires when the layout for this region is changed.
48587 * @param {Roo.LayoutRegion} this
48589 "invalidated" : true,
48591 * @event visibilitychange
48592 * Fires when this region is shown or hidden
48593 * @param {Roo.LayoutRegion} this
48594 * @param {Boolean} visibility true or false
48596 "visibilitychange" : true,
48598 * @event paneladded
48599 * Fires when a panel is added.
48600 * @param {Roo.LayoutRegion} this
48601 * @param {Roo.ContentPanel} panel The panel
48603 "paneladded" : true,
48605 * @event panelremoved
48606 * Fires when a panel is removed.
48607 * @param {Roo.LayoutRegion} this
48608 * @param {Roo.ContentPanel} panel The panel
48610 "panelremoved" : true,
48613 * Fires when this region is collapsed.
48614 * @param {Roo.LayoutRegion} this
48616 "collapsed" : true,
48619 * Fires when this region is expanded.
48620 * @param {Roo.LayoutRegion} this
48625 * Fires when this region is slid into view.
48626 * @param {Roo.LayoutRegion} this
48628 "slideshow" : true,
48631 * Fires when this region slides out of view.
48632 * @param {Roo.LayoutRegion} this
48634 "slidehide" : true,
48636 * @event panelactivated
48637 * Fires when a panel is activated.
48638 * @param {Roo.LayoutRegion} this
48639 * @param {Roo.ContentPanel} panel The activated panel
48641 "panelactivated" : true,
48644 * Fires when the user resizes this region.
48645 * @param {Roo.LayoutRegion} this
48646 * @param {Number} newSize The new size (width for east/west, height for north/south)
48650 /** A collection of panels in this region. @type Roo.util.MixedCollection */
48651 this.panels = new Roo.util.MixedCollection();
48652 this.panels.getKey = this.getPanelId.createDelegate(this);
48654 this.activePanel = null;
48655 // ensure listeners are added...
48657 if (config.listeners || config.events) {
48658 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
48659 listeners : config.listeners || {},
48660 events : config.events || {}
48664 if(skipConfig !== true){
48665 this.applyConfig(config);
48669 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
48670 getPanelId : function(p){
48674 applyConfig : function(config){
48675 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
48676 this.config = config;
48681 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
48682 * the width, for horizontal (north, south) the height.
48683 * @param {Number} newSize The new width or height
48685 resizeTo : function(newSize){
48686 var el = this.el ? this.el :
48687 (this.activePanel ? this.activePanel.getEl() : null);
48689 switch(this.position){
48692 el.setWidth(newSize);
48693 this.fireEvent("resized", this, newSize);
48697 el.setHeight(newSize);
48698 this.fireEvent("resized", this, newSize);
48704 getBox : function(){
48705 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
48708 getMargins : function(){
48709 return this.margins;
48712 updateBox : function(box){
48714 var el = this.activePanel.getEl();
48715 el.dom.style.left = box.x + "px";
48716 el.dom.style.top = box.y + "px";
48717 this.activePanel.setSize(box.width, box.height);
48721 * Returns the container element for this region.
48722 * @return {Roo.Element}
48724 getEl : function(){
48725 return this.activePanel;
48729 * Returns true if this region is currently visible.
48730 * @return {Boolean}
48732 isVisible : function(){
48733 return this.activePanel ? true : false;
48736 setActivePanel : function(panel){
48737 panel = this.getPanel(panel);
48738 if(this.activePanel && this.activePanel != panel){
48739 this.activePanel.setActiveState(false);
48740 this.activePanel.getEl().setLeftTop(-10000,-10000);
48742 this.activePanel = panel;
48743 panel.setActiveState(true);
48745 panel.setSize(this.box.width, this.box.height);
48747 this.fireEvent("panelactivated", this, panel);
48748 this.fireEvent("invalidated");
48752 * Show the specified panel.
48753 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
48754 * @return {Roo.ContentPanel} The shown panel or null
48756 showPanel : function(panel){
48757 if(panel = this.getPanel(panel)){
48758 this.setActivePanel(panel);
48764 * Get the active panel for this region.
48765 * @return {Roo.ContentPanel} The active panel or null
48767 getActivePanel : function(){
48768 return this.activePanel;
48772 * Add the passed ContentPanel(s)
48773 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
48774 * @return {Roo.ContentPanel} The panel added (if only one was added)
48776 add : function(panel){
48777 if(arguments.length > 1){
48778 for(var i = 0, len = arguments.length; i < len; i++) {
48779 this.add(arguments[i]);
48783 if(this.hasPanel(panel)){
48784 this.showPanel(panel);
48787 var el = panel.getEl();
48788 if(el.dom.parentNode != this.mgr.el.dom){
48789 this.mgr.el.dom.appendChild(el.dom);
48791 if(panel.setRegion){
48792 panel.setRegion(this);
48794 this.panels.add(panel);
48795 el.setStyle("position", "absolute");
48796 if(!panel.background){
48797 this.setActivePanel(panel);
48798 if(this.config.initialSize && this.panels.getCount()==1){
48799 this.resizeTo(this.config.initialSize);
48802 this.fireEvent("paneladded", this, panel);
48807 * Returns true if the panel is in this region.
48808 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48809 * @return {Boolean}
48811 hasPanel : function(panel){
48812 if(typeof panel == "object"){ // must be panel obj
48813 panel = panel.getId();
48815 return this.getPanel(panel) ? true : false;
48819 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
48820 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48821 * @param {Boolean} preservePanel Overrides the config preservePanel option
48822 * @return {Roo.ContentPanel} The panel that was removed
48824 remove : function(panel, preservePanel){
48825 panel = this.getPanel(panel);
48830 this.fireEvent("beforeremove", this, panel, e);
48831 if(e.cancel === true){
48834 var panelId = panel.getId();
48835 this.panels.removeKey(panelId);
48840 * Returns the panel specified or null if it's not in this region.
48841 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48842 * @return {Roo.ContentPanel}
48844 getPanel : function(id){
48845 if(typeof id == "object"){ // must be panel obj
48848 return this.panels.get(id);
48852 * Returns this regions position (north/south/east/west/center).
48855 getPosition: function(){
48856 return this.position;
48860 * Ext JS Library 1.1.1
48861 * Copyright(c) 2006-2007, Ext JS, LLC.
48863 * Originally Released Under LGPL - original licence link has changed is not relivant.
48866 * <script type="text/javascript">
48870 * @class Roo.LayoutRegion
48871 * @extends Roo.BasicLayoutRegion
48872 * This class represents a region in a layout manager.
48873 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
48874 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
48875 * @cfg {Boolean} floatable False to disable floating (defaults to true)
48876 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
48877 * @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})
48878 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
48879 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
48880 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
48881 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
48882 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
48883 * @cfg {String} title The title for the region (overrides panel titles)
48884 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
48885 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
48886 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
48887 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
48888 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
48889 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
48890 * the space available, similar to FireFox 1.5 tabs (defaults to false)
48891 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
48892 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
48893 * @cfg {Boolean} showPin True to show a pin button
48894 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
48895 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
48896 * @cfg {Boolean} disableTabTips True to disable tab tooltips
48897 * @cfg {Number} width For East/West panels
48898 * @cfg {Number} height For North/South panels
48899 * @cfg {Boolean} split To show the splitter
48900 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
48902 Roo.LayoutRegion = function(mgr, config, pos){
48903 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
48904 var dh = Roo.DomHelper;
48905 /** This region's container element
48906 * @type Roo.Element */
48907 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
48908 /** This region's title element
48909 * @type Roo.Element */
48911 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
48912 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
48913 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
48915 this.titleEl.enableDisplayMode();
48916 /** This region's title text element
48917 * @type HTMLElement */
48918 this.titleTextEl = this.titleEl.dom.firstChild;
48919 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
48920 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
48921 this.closeBtn.enableDisplayMode();
48922 this.closeBtn.on("click", this.closeClicked, this);
48923 this.closeBtn.hide();
48925 this.createBody(config);
48926 this.visible = true;
48927 this.collapsed = false;
48929 if(config.hideWhenEmpty){
48931 this.on("paneladded", this.validateVisibility, this);
48932 this.on("panelremoved", this.validateVisibility, this);
48934 this.applyConfig(config);
48937 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
48939 createBody : function(){
48940 /** This region's body element
48941 * @type Roo.Element */
48942 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
48945 applyConfig : function(c){
48946 if(c.collapsible && this.position != "center" && !this.collapsedEl){
48947 var dh = Roo.DomHelper;
48948 if(c.titlebar !== false){
48949 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
48950 this.collapseBtn.on("click", this.collapse, this);
48951 this.collapseBtn.enableDisplayMode();
48953 if(c.showPin === true || this.showPin){
48954 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
48955 this.stickBtn.enableDisplayMode();
48956 this.stickBtn.on("click", this.expand, this);
48957 this.stickBtn.hide();
48960 /** This region's collapsed element
48961 * @type Roo.Element */
48962 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
48963 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
48965 if(c.floatable !== false){
48966 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
48967 this.collapsedEl.on("click", this.collapseClick, this);
48970 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
48971 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
48972 id: "message", unselectable: "on", style:{"float":"left"}});
48973 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
48975 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
48976 this.expandBtn.on("click", this.expand, this);
48978 if(this.collapseBtn){
48979 this.collapseBtn.setVisible(c.collapsible == true);
48981 this.cmargins = c.cmargins || this.cmargins ||
48982 (this.position == "west" || this.position == "east" ?
48983 {top: 0, left: 2, right:2, bottom: 0} :
48984 {top: 2, left: 0, right:0, bottom: 2});
48985 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
48986 this.bottomTabs = c.tabPosition != "top";
48987 this.autoScroll = c.autoScroll || false;
48988 if(this.autoScroll){
48989 this.bodyEl.setStyle("overflow", "auto");
48991 this.bodyEl.setStyle("overflow", "hidden");
48993 //if(c.titlebar !== false){
48994 if((!c.titlebar && !c.title) || c.titlebar === false){
48995 this.titleEl.hide();
48997 this.titleEl.show();
48999 this.titleTextEl.innerHTML = c.title;
49003 this.duration = c.duration || .30;
49004 this.slideDuration = c.slideDuration || .45;
49007 this.collapse(true);
49014 * Returns true if this region is currently visible.
49015 * @return {Boolean}
49017 isVisible : function(){
49018 return this.visible;
49022 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
49023 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
49025 setCollapsedTitle : function(title){
49026 title = title || " ";
49027 if(this.collapsedTitleTextEl){
49028 this.collapsedTitleTextEl.innerHTML = title;
49032 getBox : function(){
49034 if(!this.collapsed){
49035 b = this.el.getBox(false, true);
49037 b = this.collapsedEl.getBox(false, true);
49042 getMargins : function(){
49043 return this.collapsed ? this.cmargins : this.margins;
49046 highlight : function(){
49047 this.el.addClass("x-layout-panel-dragover");
49050 unhighlight : function(){
49051 this.el.removeClass("x-layout-panel-dragover");
49054 updateBox : function(box){
49056 if(!this.collapsed){
49057 this.el.dom.style.left = box.x + "px";
49058 this.el.dom.style.top = box.y + "px";
49059 this.updateBody(box.width, box.height);
49061 this.collapsedEl.dom.style.left = box.x + "px";
49062 this.collapsedEl.dom.style.top = box.y + "px";
49063 this.collapsedEl.setSize(box.width, box.height);
49066 this.tabs.autoSizeTabs();
49070 updateBody : function(w, h){
49072 this.el.setWidth(w);
49073 w -= this.el.getBorderWidth("rl");
49074 if(this.config.adjustments){
49075 w += this.config.adjustments[0];
49079 this.el.setHeight(h);
49080 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
49081 h -= this.el.getBorderWidth("tb");
49082 if(this.config.adjustments){
49083 h += this.config.adjustments[1];
49085 this.bodyEl.setHeight(h);
49087 h = this.tabs.syncHeight(h);
49090 if(this.panelSize){
49091 w = w !== null ? w : this.panelSize.width;
49092 h = h !== null ? h : this.panelSize.height;
49094 if(this.activePanel){
49095 var el = this.activePanel.getEl();
49096 w = w !== null ? w : el.getWidth();
49097 h = h !== null ? h : el.getHeight();
49098 this.panelSize = {width: w, height: h};
49099 this.activePanel.setSize(w, h);
49101 if(Roo.isIE && this.tabs){
49102 this.tabs.el.repaint();
49107 * Returns the container element for this region.
49108 * @return {Roo.Element}
49110 getEl : function(){
49115 * Hides this region.
49118 if(!this.collapsed){
49119 this.el.dom.style.left = "-2000px";
49122 this.collapsedEl.dom.style.left = "-2000px";
49123 this.collapsedEl.hide();
49125 this.visible = false;
49126 this.fireEvent("visibilitychange", this, false);
49130 * Shows this region if it was previously hidden.
49133 if(!this.collapsed){
49136 this.collapsedEl.show();
49138 this.visible = true;
49139 this.fireEvent("visibilitychange", this, true);
49142 closeClicked : function(){
49143 if(this.activePanel){
49144 this.remove(this.activePanel);
49148 collapseClick : function(e){
49150 e.stopPropagation();
49153 e.stopPropagation();
49159 * Collapses this region.
49160 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
49162 collapse : function(skipAnim){
49163 if(this.collapsed) return;
49164 this.collapsed = true;
49166 this.split.el.hide();
49168 if(this.config.animate && skipAnim !== true){
49169 this.fireEvent("invalidated", this);
49170 this.animateCollapse();
49172 this.el.setLocation(-20000,-20000);
49174 this.collapsedEl.show();
49175 this.fireEvent("collapsed", this);
49176 this.fireEvent("invalidated", this);
49180 animateCollapse : function(){
49185 * Expands this region if it was previously collapsed.
49186 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
49187 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
49189 expand : function(e, skipAnim){
49190 if(e) e.stopPropagation();
49191 if(!this.collapsed || this.el.hasActiveFx()) return;
49193 this.afterSlideIn();
49196 this.collapsed = false;
49197 if(this.config.animate && skipAnim !== true){
49198 this.animateExpand();
49202 this.split.el.show();
49204 this.collapsedEl.setLocation(-2000,-2000);
49205 this.collapsedEl.hide();
49206 this.fireEvent("invalidated", this);
49207 this.fireEvent("expanded", this);
49211 animateExpand : function(){
49215 initTabs : function()
49217 this.bodyEl.setStyle("overflow", "hidden");
49218 var ts = new Roo.TabPanel(
49221 tabPosition: this.bottomTabs ? 'bottom' : 'top',
49222 disableTooltips: this.config.disableTabTips,
49223 toolbar : this.config.toolbar
49226 if(this.config.hideTabs){
49227 ts.stripWrap.setDisplayed(false);
49230 ts.resizeTabs = this.config.resizeTabs === true;
49231 ts.minTabWidth = this.config.minTabWidth || 40;
49232 ts.maxTabWidth = this.config.maxTabWidth || 250;
49233 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
49234 ts.monitorResize = false;
49235 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49236 ts.bodyEl.addClass('x-layout-tabs-body');
49237 this.panels.each(this.initPanelAsTab, this);
49240 initPanelAsTab : function(panel){
49241 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
49242 this.config.closeOnTab && panel.isClosable());
49243 if(panel.tabTip !== undefined){
49244 ti.setTooltip(panel.tabTip);
49246 ti.on("activate", function(){
49247 this.setActivePanel(panel);
49249 if(this.config.closeOnTab){
49250 ti.on("beforeclose", function(t, e){
49252 this.remove(panel);
49258 updatePanelTitle : function(panel, title){
49259 if(this.activePanel == panel){
49260 this.updateTitle(title);
49263 var ti = this.tabs.getTab(panel.getEl().id);
49265 if(panel.tabTip !== undefined){
49266 ti.setTooltip(panel.tabTip);
49271 updateTitle : function(title){
49272 if(this.titleTextEl && !this.config.title){
49273 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
49277 setActivePanel : function(panel){
49278 panel = this.getPanel(panel);
49279 if(this.activePanel && this.activePanel != panel){
49280 this.activePanel.setActiveState(false);
49282 this.activePanel = panel;
49283 panel.setActiveState(true);
49284 if(this.panelSize){
49285 panel.setSize(this.panelSize.width, this.panelSize.height);
49288 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
49290 this.updateTitle(panel.getTitle());
49292 this.fireEvent("invalidated", this);
49294 this.fireEvent("panelactivated", this, panel);
49298 * Shows the specified panel.
49299 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
49300 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
49302 showPanel : function(panel){
49303 if(panel = this.getPanel(panel)){
49305 var tab = this.tabs.getTab(panel.getEl().id);
49306 if(tab.isHidden()){
49307 this.tabs.unhideTab(tab.id);
49311 this.setActivePanel(panel);
49318 * Get the active panel for this region.
49319 * @return {Roo.ContentPanel} The active panel or null
49321 getActivePanel : function(){
49322 return this.activePanel;
49325 validateVisibility : function(){
49326 if(this.panels.getCount() < 1){
49327 this.updateTitle(" ");
49328 this.closeBtn.hide();
49331 if(!this.isVisible()){
49338 * Adds the passed ContentPanel(s) to this region.
49339 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49340 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
49342 add : function(panel){
49343 if(arguments.length > 1){
49344 for(var i = 0, len = arguments.length; i < len; i++) {
49345 this.add(arguments[i]);
49349 if(this.hasPanel(panel)){
49350 this.showPanel(panel);
49353 panel.setRegion(this);
49354 this.panels.add(panel);
49355 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
49356 this.bodyEl.dom.appendChild(panel.getEl().dom);
49357 if(panel.background !== true){
49358 this.setActivePanel(panel);
49360 this.fireEvent("paneladded", this, panel);
49366 this.initPanelAsTab(panel);
49368 if(panel.background !== true){
49369 this.tabs.activate(panel.getEl().id);
49371 this.fireEvent("paneladded", this, panel);
49376 * Hides the tab for the specified panel.
49377 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49379 hidePanel : function(panel){
49380 if(this.tabs && (panel = this.getPanel(panel))){
49381 this.tabs.hideTab(panel.getEl().id);
49386 * Unhides the tab for a previously hidden panel.
49387 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49389 unhidePanel : function(panel){
49390 if(this.tabs && (panel = this.getPanel(panel))){
49391 this.tabs.unhideTab(panel.getEl().id);
49395 clearPanels : function(){
49396 while(this.panels.getCount() > 0){
49397 this.remove(this.panels.first());
49402 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49403 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49404 * @param {Boolean} preservePanel Overrides the config preservePanel option
49405 * @return {Roo.ContentPanel} The panel that was removed
49407 remove : function(panel, preservePanel){
49408 panel = this.getPanel(panel);
49413 this.fireEvent("beforeremove", this, panel, e);
49414 if(e.cancel === true){
49417 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
49418 var panelId = panel.getId();
49419 this.panels.removeKey(panelId);
49421 document.body.appendChild(panel.getEl().dom);
49424 this.tabs.removeTab(panel.getEl().id);
49425 }else if (!preservePanel){
49426 this.bodyEl.dom.removeChild(panel.getEl().dom);
49428 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
49429 var p = this.panels.first();
49430 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
49431 tempEl.appendChild(p.getEl().dom);
49432 this.bodyEl.update("");
49433 this.bodyEl.dom.appendChild(p.getEl().dom);
49435 this.updateTitle(p.getTitle());
49437 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49438 this.setActivePanel(p);
49440 panel.setRegion(null);
49441 if(this.activePanel == panel){
49442 this.activePanel = null;
49444 if(this.config.autoDestroy !== false && preservePanel !== true){
49445 try{panel.destroy();}catch(e){}
49447 this.fireEvent("panelremoved", this, panel);
49452 * Returns the TabPanel component used by this region
49453 * @return {Roo.TabPanel}
49455 getTabs : function(){
49459 createTool : function(parentEl, className){
49460 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
49461 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
49462 btn.addClassOnOver("x-layout-tools-button-over");
49467 * Ext JS Library 1.1.1
49468 * Copyright(c) 2006-2007, Ext JS, LLC.
49470 * Originally Released Under LGPL - original licence link has changed is not relivant.
49473 * <script type="text/javascript">
49479 * @class Roo.SplitLayoutRegion
49480 * @extends Roo.LayoutRegion
49481 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
49483 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
49484 this.cursor = cursor;
49485 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
49488 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
49489 splitTip : "Drag to resize.",
49490 collapsibleSplitTip : "Drag to resize. Double click to hide.",
49491 useSplitTips : false,
49493 applyConfig : function(config){
49494 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
49497 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
49498 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
49499 /** The SplitBar for this region
49500 * @type Roo.SplitBar */
49501 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
49502 this.split.on("moved", this.onSplitMove, this);
49503 this.split.useShim = config.useShim === true;
49504 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
49505 if(this.useSplitTips){
49506 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
49508 if(config.collapsible){
49509 this.split.el.on("dblclick", this.collapse, this);
49512 if(typeof config.minSize != "undefined"){
49513 this.split.minSize = config.minSize;
49515 if(typeof config.maxSize != "undefined"){
49516 this.split.maxSize = config.maxSize;
49518 if(config.hideWhenEmpty || config.hidden || config.collapsed){
49519 this.hideSplitter();
49524 getHMaxSize : function(){
49525 var cmax = this.config.maxSize || 10000;
49526 var center = this.mgr.getRegion("center");
49527 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
49530 getVMaxSize : function(){
49531 var cmax = this.config.maxSize || 10000;
49532 var center = this.mgr.getRegion("center");
49533 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
49536 onSplitMove : function(split, newSize){
49537 this.fireEvent("resized", this, newSize);
49541 * Returns the {@link Roo.SplitBar} for this region.
49542 * @return {Roo.SplitBar}
49544 getSplitBar : function(){
49549 this.hideSplitter();
49550 Roo.SplitLayoutRegion.superclass.hide.call(this);
49553 hideSplitter : function(){
49555 this.split.el.setLocation(-2000,-2000);
49556 this.split.el.hide();
49562 this.split.el.show();
49564 Roo.SplitLayoutRegion.superclass.show.call(this);
49567 beforeSlide: function(){
49568 if(Roo.isGecko){// firefox overflow auto bug workaround
49569 this.bodyEl.clip();
49570 if(this.tabs) this.tabs.bodyEl.clip();
49571 if(this.activePanel){
49572 this.activePanel.getEl().clip();
49574 if(this.activePanel.beforeSlide){
49575 this.activePanel.beforeSlide();
49581 afterSlide : function(){
49582 if(Roo.isGecko){// firefox overflow auto bug workaround
49583 this.bodyEl.unclip();
49584 if(this.tabs) this.tabs.bodyEl.unclip();
49585 if(this.activePanel){
49586 this.activePanel.getEl().unclip();
49587 if(this.activePanel.afterSlide){
49588 this.activePanel.afterSlide();
49594 initAutoHide : function(){
49595 if(this.autoHide !== false){
49596 if(!this.autoHideHd){
49597 var st = new Roo.util.DelayedTask(this.slideIn, this);
49598 this.autoHideHd = {
49599 "mouseout": function(e){
49600 if(!e.within(this.el, true)){
49604 "mouseover" : function(e){
49610 this.el.on(this.autoHideHd);
49614 clearAutoHide : function(){
49615 if(this.autoHide !== false){
49616 this.el.un("mouseout", this.autoHideHd.mouseout);
49617 this.el.un("mouseover", this.autoHideHd.mouseover);
49621 clearMonitor : function(){
49622 Roo.get(document).un("click", this.slideInIf, this);
49625 // these names are backwards but not changed for compat
49626 slideOut : function(){
49627 if(this.isSlid || this.el.hasActiveFx()){
49630 this.isSlid = true;
49631 if(this.collapseBtn){
49632 this.collapseBtn.hide();
49634 this.closeBtnState = this.closeBtn.getStyle('display');
49635 this.closeBtn.hide();
49637 this.stickBtn.show();
49640 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
49641 this.beforeSlide();
49642 this.el.setStyle("z-index", 10001);
49643 this.el.slideIn(this.getSlideAnchor(), {
49644 callback: function(){
49646 this.initAutoHide();
49647 Roo.get(document).on("click", this.slideInIf, this);
49648 this.fireEvent("slideshow", this);
49655 afterSlideIn : function(){
49656 this.clearAutoHide();
49657 this.isSlid = false;
49658 this.clearMonitor();
49659 this.el.setStyle("z-index", "");
49660 if(this.collapseBtn){
49661 this.collapseBtn.show();
49663 this.closeBtn.setStyle('display', this.closeBtnState);
49665 this.stickBtn.hide();
49667 this.fireEvent("slidehide", this);
49670 slideIn : function(cb){
49671 if(!this.isSlid || this.el.hasActiveFx()){
49675 this.isSlid = false;
49676 this.beforeSlide();
49677 this.el.slideOut(this.getSlideAnchor(), {
49678 callback: function(){
49679 this.el.setLeftTop(-10000, -10000);
49681 this.afterSlideIn();
49689 slideInIf : function(e){
49690 if(!e.within(this.el)){
49695 animateCollapse : function(){
49696 this.beforeSlide();
49697 this.el.setStyle("z-index", 20000);
49698 var anchor = this.getSlideAnchor();
49699 this.el.slideOut(anchor, {
49700 callback : function(){
49701 this.el.setStyle("z-index", "");
49702 this.collapsedEl.slideIn(anchor, {duration:.3});
49704 this.el.setLocation(-10000,-10000);
49706 this.fireEvent("collapsed", this);
49713 animateExpand : function(){
49714 this.beforeSlide();
49715 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
49716 this.el.setStyle("z-index", 20000);
49717 this.collapsedEl.hide({
49720 this.el.slideIn(this.getSlideAnchor(), {
49721 callback : function(){
49722 this.el.setStyle("z-index", "");
49725 this.split.el.show();
49727 this.fireEvent("invalidated", this);
49728 this.fireEvent("expanded", this);
49756 getAnchor : function(){
49757 return this.anchors[this.position];
49760 getCollapseAnchor : function(){
49761 return this.canchors[this.position];
49764 getSlideAnchor : function(){
49765 return this.sanchors[this.position];
49768 getAlignAdj : function(){
49769 var cm = this.cmargins;
49770 switch(this.position){
49786 getExpandAdj : function(){
49787 var c = this.collapsedEl, cm = this.cmargins;
49788 switch(this.position){
49790 return [-(cm.right+c.getWidth()+cm.left), 0];
49793 return [cm.right+c.getWidth()+cm.left, 0];
49796 return [0, -(cm.top+cm.bottom+c.getHeight())];
49799 return [0, cm.top+cm.bottom+c.getHeight()];
49805 * Ext JS Library 1.1.1
49806 * Copyright(c) 2006-2007, Ext JS, LLC.
49808 * Originally Released Under LGPL - original licence link has changed is not relivant.
49811 * <script type="text/javascript">
49814 * These classes are private internal classes
49816 Roo.CenterLayoutRegion = function(mgr, config){
49817 Roo.LayoutRegion.call(this, mgr, config, "center");
49818 this.visible = true;
49819 this.minWidth = config.minWidth || 20;
49820 this.minHeight = config.minHeight || 20;
49823 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
49825 // center panel can't be hidden
49829 // center panel can't be hidden
49832 getMinWidth: function(){
49833 return this.minWidth;
49836 getMinHeight: function(){
49837 return this.minHeight;
49842 Roo.NorthLayoutRegion = function(mgr, config){
49843 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
49845 this.split.placement = Roo.SplitBar.TOP;
49846 this.split.orientation = Roo.SplitBar.VERTICAL;
49847 this.split.el.addClass("x-layout-split-v");
49849 var size = config.initialSize || config.height;
49850 if(typeof size != "undefined"){
49851 this.el.setHeight(size);
49854 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
49855 orientation: Roo.SplitBar.VERTICAL,
49856 getBox : function(){
49857 if(this.collapsed){
49858 return this.collapsedEl.getBox();
49860 var box = this.el.getBox();
49862 box.height += this.split.el.getHeight();
49867 updateBox : function(box){
49868 if(this.split && !this.collapsed){
49869 box.height -= this.split.el.getHeight();
49870 this.split.el.setLeft(box.x);
49871 this.split.el.setTop(box.y+box.height);
49872 this.split.el.setWidth(box.width);
49874 if(this.collapsed){
49875 this.updateBody(box.width, null);
49877 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49881 Roo.SouthLayoutRegion = function(mgr, config){
49882 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
49884 this.split.placement = Roo.SplitBar.BOTTOM;
49885 this.split.orientation = Roo.SplitBar.VERTICAL;
49886 this.split.el.addClass("x-layout-split-v");
49888 var size = config.initialSize || config.height;
49889 if(typeof size != "undefined"){
49890 this.el.setHeight(size);
49893 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
49894 orientation: Roo.SplitBar.VERTICAL,
49895 getBox : function(){
49896 if(this.collapsed){
49897 return this.collapsedEl.getBox();
49899 var box = this.el.getBox();
49901 var sh = this.split.el.getHeight();
49908 updateBox : function(box){
49909 if(this.split && !this.collapsed){
49910 var sh = this.split.el.getHeight();
49913 this.split.el.setLeft(box.x);
49914 this.split.el.setTop(box.y-sh);
49915 this.split.el.setWidth(box.width);
49917 if(this.collapsed){
49918 this.updateBody(box.width, null);
49920 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49924 Roo.EastLayoutRegion = function(mgr, config){
49925 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
49927 this.split.placement = Roo.SplitBar.RIGHT;
49928 this.split.orientation = Roo.SplitBar.HORIZONTAL;
49929 this.split.el.addClass("x-layout-split-h");
49931 var size = config.initialSize || config.width;
49932 if(typeof size != "undefined"){
49933 this.el.setWidth(size);
49936 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
49937 orientation: Roo.SplitBar.HORIZONTAL,
49938 getBox : function(){
49939 if(this.collapsed){
49940 return this.collapsedEl.getBox();
49942 var box = this.el.getBox();
49944 var sw = this.split.el.getWidth();
49951 updateBox : function(box){
49952 if(this.split && !this.collapsed){
49953 var sw = this.split.el.getWidth();
49955 this.split.el.setLeft(box.x);
49956 this.split.el.setTop(box.y);
49957 this.split.el.setHeight(box.height);
49960 if(this.collapsed){
49961 this.updateBody(null, box.height);
49963 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49967 Roo.WestLayoutRegion = function(mgr, config){
49968 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
49970 this.split.placement = Roo.SplitBar.LEFT;
49971 this.split.orientation = Roo.SplitBar.HORIZONTAL;
49972 this.split.el.addClass("x-layout-split-h");
49974 var size = config.initialSize || config.width;
49975 if(typeof size != "undefined"){
49976 this.el.setWidth(size);
49979 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
49980 orientation: Roo.SplitBar.HORIZONTAL,
49981 getBox : function(){
49982 if(this.collapsed){
49983 return this.collapsedEl.getBox();
49985 var box = this.el.getBox();
49987 box.width += this.split.el.getWidth();
49992 updateBox : function(box){
49993 if(this.split && !this.collapsed){
49994 var sw = this.split.el.getWidth();
49996 this.split.el.setLeft(box.x+box.width);
49997 this.split.el.setTop(box.y);
49998 this.split.el.setHeight(box.height);
50000 if(this.collapsed){
50001 this.updateBody(null, box.height);
50003 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50008 * Ext JS Library 1.1.1
50009 * Copyright(c) 2006-2007, Ext JS, LLC.
50011 * Originally Released Under LGPL - original licence link has changed is not relivant.
50014 * <script type="text/javascript">
50019 * Private internal class for reading and applying state
50021 Roo.LayoutStateManager = function(layout){
50022 // default empty state
50031 Roo.LayoutStateManager.prototype = {
50032 init : function(layout, provider){
50033 this.provider = provider;
50034 var state = provider.get(layout.id+"-layout-state");
50036 var wasUpdating = layout.isUpdating();
50038 layout.beginUpdate();
50040 for(var key in state){
50041 if(typeof state[key] != "function"){
50042 var rstate = state[key];
50043 var r = layout.getRegion(key);
50046 r.resizeTo(rstate.size);
50048 if(rstate.collapsed == true){
50051 r.expand(null, true);
50057 layout.endUpdate();
50059 this.state = state;
50061 this.layout = layout;
50062 layout.on("regionresized", this.onRegionResized, this);
50063 layout.on("regioncollapsed", this.onRegionCollapsed, this);
50064 layout.on("regionexpanded", this.onRegionExpanded, this);
50067 storeState : function(){
50068 this.provider.set(this.layout.id+"-layout-state", this.state);
50071 onRegionResized : function(region, newSize){
50072 this.state[region.getPosition()].size = newSize;
50076 onRegionCollapsed : function(region){
50077 this.state[region.getPosition()].collapsed = true;
50081 onRegionExpanded : function(region){
50082 this.state[region.getPosition()].collapsed = false;
50087 * Ext JS Library 1.1.1
50088 * Copyright(c) 2006-2007, Ext JS, LLC.
50090 * Originally Released Under LGPL - original licence link has changed is not relivant.
50093 * <script type="text/javascript">
50096 * @class Roo.ContentPanel
50097 * @extends Roo.util.Observable
50098 * A basic ContentPanel element.
50099 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
50100 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
50101 * @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
50102 * @cfg {Boolean} closable True if the panel can be closed/removed
50103 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
50104 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
50105 * @cfg {Toolbar} toolbar A toolbar for this panel
50106 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
50107 * @cfg {String} title The title for this panel
50108 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
50109 * @cfg {String} url Calls {@link #setUrl} with this value
50110 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
50111 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
50112 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
50113 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
50116 * Create a new ContentPanel.
50117 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
50118 * @param {String/Object} config A string to set only the title or a config object
50119 * @param {String} content (optional) Set the HTML content for this panel
50120 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
50122 Roo.ContentPanel = function(el, config, content){
50126 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
50130 if (config && config.parentLayout) {
50131 el = config.parentLayout.el.createChild();
50134 if(el.autoCreate){ // xtype is available if this is called from factory
50138 this.el = Roo.get(el);
50139 if(!this.el && config && config.autoCreate){
50140 if(typeof config.autoCreate == "object"){
50141 if(!config.autoCreate.id){
50142 config.autoCreate.id = config.id||el;
50144 this.el = Roo.DomHelper.append(document.body,
50145 config.autoCreate, true);
50147 this.el = Roo.DomHelper.append(document.body,
50148 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
50151 this.closable = false;
50152 this.loaded = false;
50153 this.active = false;
50154 if(typeof config == "string"){
50155 this.title = config;
50157 Roo.apply(this, config);
50160 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
50161 this.wrapEl = this.el.wrap();
50162 this.toolbar.container = this.el.insertSibling(false, 'before');
50163 this.toolbar = new Roo.Toolbar(this.toolbar);
50166 // xtype created footer. - not sure if will work as we normally have to render first..
50167 if (this.footer && !this.footer.el && this.footer.xtype) {
50168 if (!this.wrapEl) {
50169 this.wrapEl = this.el.wrap();
50172 this.footer.container = this.wrapEl.createChild();
50174 this.footer = Roo.factory(this.footer, Roo);
50179 this.resizeEl = Roo.get(this.resizeEl, true);
50181 this.resizeEl = this.el;
50183 // handle view.xtype
50191 * Fires when this panel is activated.
50192 * @param {Roo.ContentPanel} this
50196 * @event deactivate
50197 * Fires when this panel is activated.
50198 * @param {Roo.ContentPanel} this
50200 "deactivate" : true,
50204 * Fires when this panel is resized if fitToFrame is true.
50205 * @param {Roo.ContentPanel} this
50206 * @param {Number} width The width after any component adjustments
50207 * @param {Number} height The height after any component adjustments
50213 * Fires when this tab is created
50214 * @param {Roo.ContentPanel} this
50225 if(this.autoScroll){
50226 this.resizeEl.setStyle("overflow", "auto");
50228 // fix randome scrolling
50229 this.el.on('scroll', function() {
50230 Roo.log('fix random scolling');
50231 this.scrollTo('top',0);
50234 content = content || this.content;
50236 this.setContent(content);
50238 if(config && config.url){
50239 this.setUrl(this.url, this.params, this.loadOnce);
50244 Roo.ContentPanel.superclass.constructor.call(this);
50246 if (this.view && typeof(this.view.xtype) != 'undefined') {
50247 this.view.el = this.el.appendChild(document.createElement("div"));
50248 this.view = Roo.factory(this.view);
50249 this.view.render && this.view.render(false, '');
50253 this.fireEvent('render', this);
50256 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
50258 setRegion : function(region){
50259 this.region = region;
50261 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
50263 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
50268 * Returns the toolbar for this Panel if one was configured.
50269 * @return {Roo.Toolbar}
50271 getToolbar : function(){
50272 return this.toolbar;
50275 setActiveState : function(active){
50276 this.active = active;
50278 this.fireEvent("deactivate", this);
50280 this.fireEvent("activate", this);
50284 * Updates this panel's element
50285 * @param {String} content The new content
50286 * @param {Boolean} loadScripts (optional) true to look for and process scripts
50288 setContent : function(content, loadScripts){
50289 this.el.update(content, loadScripts);
50292 ignoreResize : function(w, h){
50293 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
50296 this.lastSize = {width: w, height: h};
50301 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
50302 * @return {Roo.UpdateManager} The UpdateManager
50304 getUpdateManager : function(){
50305 return this.el.getUpdateManager();
50308 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
50309 * @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:
50312 url: "your-url.php",
50313 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
50314 callback: yourFunction,
50315 scope: yourObject, //(optional scope)
50318 text: "Loading...",
50323 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
50324 * 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.
50325 * @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}
50326 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
50327 * @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.
50328 * @return {Roo.ContentPanel} this
50331 var um = this.el.getUpdateManager();
50332 um.update.apply(um, arguments);
50338 * 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.
50339 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
50340 * @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)
50341 * @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)
50342 * @return {Roo.UpdateManager} The UpdateManager
50344 setUrl : function(url, params, loadOnce){
50345 if(this.refreshDelegate){
50346 this.removeListener("activate", this.refreshDelegate);
50348 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
50349 this.on("activate", this.refreshDelegate);
50350 return this.el.getUpdateManager();
50353 _handleRefresh : function(url, params, loadOnce){
50354 if(!loadOnce || !this.loaded){
50355 var updater = this.el.getUpdateManager();
50356 updater.update(url, params, this._setLoaded.createDelegate(this));
50360 _setLoaded : function(){
50361 this.loaded = true;
50365 * Returns this panel's id
50368 getId : function(){
50373 * Returns this panel's element - used by regiosn to add.
50374 * @return {Roo.Element}
50376 getEl : function(){
50377 return this.wrapEl || this.el;
50380 adjustForComponents : function(width, height)
50382 //Roo.log('adjustForComponents ');
50383 if(this.resizeEl != this.el){
50384 width -= this.el.getFrameWidth('lr');
50385 height -= this.el.getFrameWidth('tb');
50388 var te = this.toolbar.getEl();
50389 height -= te.getHeight();
50390 te.setWidth(width);
50393 var te = this.footer.getEl();
50394 Roo.log("footer:" + te.getHeight());
50396 height -= te.getHeight();
50397 te.setWidth(width);
50401 if(this.adjustments){
50402 width += this.adjustments[0];
50403 height += this.adjustments[1];
50405 return {"width": width, "height": height};
50408 setSize : function(width, height){
50409 if(this.fitToFrame && !this.ignoreResize(width, height)){
50410 if(this.fitContainer && this.resizeEl != this.el){
50411 this.el.setSize(width, height);
50413 var size = this.adjustForComponents(width, height);
50414 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
50415 this.fireEvent('resize', this, size.width, size.height);
50420 * Returns this panel's title
50423 getTitle : function(){
50428 * Set this panel's title
50429 * @param {String} title
50431 setTitle : function(title){
50432 this.title = title;
50434 this.region.updatePanelTitle(this, title);
50439 * Returns true is this panel was configured to be closable
50440 * @return {Boolean}
50442 isClosable : function(){
50443 return this.closable;
50446 beforeSlide : function(){
50448 this.resizeEl.clip();
50451 afterSlide : function(){
50453 this.resizeEl.unclip();
50457 * Force a content refresh from the URL specified in the {@link #setUrl} method.
50458 * Will fail silently if the {@link #setUrl} method has not been called.
50459 * This does not activate the panel, just updates its content.
50461 refresh : function(){
50462 if(this.refreshDelegate){
50463 this.loaded = false;
50464 this.refreshDelegate();
50469 * Destroys this panel
50471 destroy : function(){
50472 this.el.removeAllListeners();
50473 var tempEl = document.createElement("span");
50474 tempEl.appendChild(this.el.dom);
50475 tempEl.innerHTML = "";
50481 * form - if the content panel contains a form - this is a reference to it.
50482 * @type {Roo.form.Form}
50486 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
50487 * This contains a reference to it.
50493 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
50503 * @param {Object} cfg Xtype definition of item to add.
50506 addxtype : function(cfg) {
50508 if (cfg.xtype.match(/^Form$/)) {
50511 //if (this.footer) {
50512 // el = this.footer.container.insertSibling(false, 'before');
50514 el = this.el.createChild();
50517 this.form = new Roo.form.Form(cfg);
50520 if ( this.form.allItems.length) this.form.render(el.dom);
50523 // should only have one of theses..
50524 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
50525 // views.. should not be just added - used named prop 'view''
50527 cfg.el = this.el.appendChild(document.createElement("div"));
50530 var ret = new Roo.factory(cfg);
50532 ret.render && ret.render(false, ''); // render blank..
50541 * @class Roo.GridPanel
50542 * @extends Roo.ContentPanel
50544 * Create a new GridPanel.
50545 * @param {Roo.grid.Grid} grid The grid for this panel
50546 * @param {String/Object} config A string to set only the panel's title, or a config object
50548 Roo.GridPanel = function(grid, config){
50551 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
50552 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
50554 this.wrapper.dom.appendChild(grid.getGridEl().dom);
50556 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
50559 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
50561 // xtype created footer. - not sure if will work as we normally have to render first..
50562 if (this.footer && !this.footer.el && this.footer.xtype) {
50564 this.footer.container = this.grid.getView().getFooterPanel(true);
50565 this.footer.dataSource = this.grid.dataSource;
50566 this.footer = Roo.factory(this.footer, Roo);
50570 grid.monitorWindowResize = false; // turn off autosizing
50571 grid.autoHeight = false;
50572 grid.autoWidth = false;
50574 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
50577 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
50578 getId : function(){
50579 return this.grid.id;
50583 * Returns the grid for this panel
50584 * @return {Roo.grid.Grid}
50586 getGrid : function(){
50590 setSize : function(width, height){
50591 if(!this.ignoreResize(width, height)){
50592 var grid = this.grid;
50593 var size = this.adjustForComponents(width, height);
50594 grid.getGridEl().setSize(size.width, size.height);
50599 beforeSlide : function(){
50600 this.grid.getView().scroller.clip();
50603 afterSlide : function(){
50604 this.grid.getView().scroller.unclip();
50607 destroy : function(){
50608 this.grid.destroy();
50610 Roo.GridPanel.superclass.destroy.call(this);
50616 * @class Roo.NestedLayoutPanel
50617 * @extends Roo.ContentPanel
50619 * Create a new NestedLayoutPanel.
50622 * @param {Roo.BorderLayout} layout The layout for this panel
50623 * @param {String/Object} config A string to set only the title or a config object
50625 Roo.NestedLayoutPanel = function(layout, config)
50627 // construct with only one argument..
50628 /* FIXME - implement nicer consturctors
50629 if (layout.layout) {
50631 layout = config.layout;
50632 delete config.layout;
50634 if (layout.xtype && !layout.getEl) {
50635 // then layout needs constructing..
50636 layout = Roo.factory(layout, Roo);
50641 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
50643 layout.monitorWindowResize = false; // turn off autosizing
50644 this.layout = layout;
50645 this.layout.getEl().addClass("x-layout-nested-layout");
50652 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
50654 setSize : function(width, height){
50655 if(!this.ignoreResize(width, height)){
50656 var size = this.adjustForComponents(width, height);
50657 var el = this.layout.getEl();
50658 el.setSize(size.width, size.height);
50659 var touch = el.dom.offsetWidth;
50660 this.layout.layout();
50661 // ie requires a double layout on the first pass
50662 if(Roo.isIE && !this.initialized){
50663 this.initialized = true;
50664 this.layout.layout();
50669 // activate all subpanels if not currently active..
50671 setActiveState : function(active){
50672 this.active = active;
50674 this.fireEvent("deactivate", this);
50678 this.fireEvent("activate", this);
50679 // not sure if this should happen before or after..
50680 if (!this.layout) {
50681 return; // should not happen..
50684 for (var r in this.layout.regions) {
50685 reg = this.layout.getRegion(r);
50686 if (reg.getActivePanel()) {
50687 //reg.showPanel(reg.getActivePanel()); // force it to activate..
50688 reg.setActivePanel(reg.getActivePanel());
50691 if (!reg.panels.length) {
50694 reg.showPanel(reg.getPanel(0));
50703 * Returns the nested BorderLayout for this panel
50704 * @return {Roo.BorderLayout}
50706 getLayout : function(){
50707 return this.layout;
50711 * Adds a xtype elements to the layout of the nested panel
50715 xtype : 'ContentPanel',
50722 xtype : 'NestedLayoutPanel',
50728 items : [ ... list of content panels or nested layout panels.. ]
50732 * @param {Object} cfg Xtype definition of item to add.
50734 addxtype : function(cfg) {
50735 return this.layout.addxtype(cfg);
50740 Roo.ScrollPanel = function(el, config, content){
50741 config = config || {};
50742 config.fitToFrame = true;
50743 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
50745 this.el.dom.style.overflow = "hidden";
50746 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
50747 this.el.removeClass("x-layout-inactive-content");
50748 this.el.on("mousewheel", this.onWheel, this);
50750 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
50751 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
50752 up.unselectable(); down.unselectable();
50753 up.on("click", this.scrollUp, this);
50754 down.on("click", this.scrollDown, this);
50755 up.addClassOnOver("x-scroller-btn-over");
50756 down.addClassOnOver("x-scroller-btn-over");
50757 up.addClassOnClick("x-scroller-btn-click");
50758 down.addClassOnClick("x-scroller-btn-click");
50759 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
50761 this.resizeEl = this.el;
50762 this.el = wrap; this.up = up; this.down = down;
50765 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
50767 wheelIncrement : 5,
50768 scrollUp : function(){
50769 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
50772 scrollDown : function(){
50773 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
50776 afterScroll : function(){
50777 var el = this.resizeEl;
50778 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
50779 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
50780 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
50783 setSize : function(){
50784 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
50785 this.afterScroll();
50788 onWheel : function(e){
50789 var d = e.getWheelDelta();
50790 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
50791 this.afterScroll();
50795 setContent : function(content, loadScripts){
50796 this.resizeEl.update(content, loadScripts);
50810 * @class Roo.TreePanel
50811 * @extends Roo.ContentPanel
50813 * Create a new TreePanel. - defaults to fit/scoll contents.
50814 * @param {String/Object} config A string to set only the panel's title, or a config object
50815 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
50817 Roo.TreePanel = function(config){
50818 var el = config.el;
50819 var tree = config.tree;
50820 delete config.tree;
50821 delete config.el; // hopefull!
50823 // wrapper for IE7 strict & safari scroll issue
50825 var treeEl = el.createChild();
50826 config.resizeEl = treeEl;
50830 Roo.TreePanel.superclass.constructor.call(this, el, config);
50833 this.tree = new Roo.tree.TreePanel(treeEl , tree);
50834 //console.log(tree);
50835 this.on('activate', function()
50837 if (this.tree.rendered) {
50840 //console.log('render tree');
50841 this.tree.render();
50843 // this should not be needed.. - it's actually the 'el' that resizes?
50844 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
50846 //this.on('resize', function (cp, w, h) {
50847 // this.tree.innerCt.setWidth(w);
50848 // this.tree.innerCt.setHeight(h);
50849 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
50856 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
50873 * Ext JS Library 1.1.1
50874 * Copyright(c) 2006-2007, Ext JS, LLC.
50876 * Originally Released Under LGPL - original licence link has changed is not relivant.
50879 * <script type="text/javascript">
50884 * @class Roo.ReaderLayout
50885 * @extends Roo.BorderLayout
50886 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
50887 * center region containing two nested regions (a top one for a list view and one for item preview below),
50888 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
50889 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
50890 * expedites the setup of the overall layout and regions for this common application style.
50893 var reader = new Roo.ReaderLayout();
50894 var CP = Roo.ContentPanel; // shortcut for adding
50896 reader.beginUpdate();
50897 reader.add("north", new CP("north", "North"));
50898 reader.add("west", new CP("west", {title: "West"}));
50899 reader.add("east", new CP("east", {title: "East"}));
50901 reader.regions.listView.add(new CP("listView", "List"));
50902 reader.regions.preview.add(new CP("preview", "Preview"));
50903 reader.endUpdate();
50906 * Create a new ReaderLayout
50907 * @param {Object} config Configuration options
50908 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
50909 * document.body if omitted)
50911 Roo.ReaderLayout = function(config, renderTo){
50912 var c = config || {size:{}};
50913 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
50914 north: c.north !== false ? Roo.apply({
50918 }, c.north) : false,
50919 west: c.west !== false ? Roo.apply({
50927 margins:{left:5,right:0,bottom:5,top:5},
50928 cmargins:{left:5,right:5,bottom:5,top:5}
50929 }, c.west) : false,
50930 east: c.east !== false ? Roo.apply({
50938 margins:{left:0,right:5,bottom:5,top:5},
50939 cmargins:{left:5,right:5,bottom:5,top:5}
50940 }, c.east) : false,
50941 center: Roo.apply({
50942 tabPosition: 'top',
50946 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
50950 this.el.addClass('x-reader');
50952 this.beginUpdate();
50954 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
50955 south: c.preview !== false ? Roo.apply({
50962 cmargins:{top:5,left:0, right:0, bottom:0}
50963 }, c.preview) : false,
50964 center: Roo.apply({
50970 this.add('center', new Roo.NestedLayoutPanel(inner,
50971 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
50975 this.regions.preview = inner.getRegion('south');
50976 this.regions.listView = inner.getRegion('center');
50979 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
50981 * Ext JS Library 1.1.1
50982 * Copyright(c) 2006-2007, Ext JS, LLC.
50984 * Originally Released Under LGPL - original licence link has changed is not relivant.
50987 * <script type="text/javascript">
50991 * @class Roo.grid.Grid
50992 * @extends Roo.util.Observable
50993 * This class represents the primary interface of a component based grid control.
50994 * <br><br>Usage:<pre><code>
50995 var grid = new Roo.grid.Grid("my-container-id", {
50998 selModel: mySelectionModel,
50999 autoSizeColumns: true,
51000 monitorWindowResize: false,
51001 trackMouseOver: true
51006 * <b>Common Problems:</b><br/>
51007 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
51008 * element will correct this<br/>
51009 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
51010 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
51011 * are unpredictable.<br/>
51012 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
51013 * grid to calculate dimensions/offsets.<br/>
51015 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51016 * The container MUST have some type of size defined for the grid to fill. The container will be
51017 * automatically set to position relative if it isn't already.
51018 * @param {Object} config A config object that sets properties on this grid.
51020 Roo.grid.Grid = function(container, config){
51021 // initialize the container
51022 this.container = Roo.get(container);
51023 this.container.update("");
51024 this.container.setStyle("overflow", "hidden");
51025 this.container.addClass('x-grid-container');
51027 this.id = this.container.id;
51029 Roo.apply(this, config);
51030 // check and correct shorthanded configs
51032 this.dataSource = this.ds;
51036 this.colModel = this.cm;
51040 this.selModel = this.sm;
51044 if (this.selModel) {
51045 this.selModel = Roo.factory(this.selModel, Roo.grid);
51046 this.sm = this.selModel;
51047 this.sm.xmodule = this.xmodule || false;
51049 if (typeof(this.colModel.config) == 'undefined') {
51050 this.colModel = new Roo.grid.ColumnModel(this.colModel);
51051 this.cm = this.colModel;
51052 this.cm.xmodule = this.xmodule || false;
51054 if (this.dataSource) {
51055 this.dataSource= Roo.factory(this.dataSource, Roo.data);
51056 this.ds = this.dataSource;
51057 this.ds.xmodule = this.xmodule || false;
51064 this.container.setWidth(this.width);
51068 this.container.setHeight(this.height);
51075 * The raw click event for the entire grid.
51076 * @param {Roo.EventObject} e
51081 * The raw dblclick event for the entire grid.
51082 * @param {Roo.EventObject} e
51086 * @event contextmenu
51087 * The raw contextmenu event for the entire grid.
51088 * @param {Roo.EventObject} e
51090 "contextmenu" : true,
51093 * The raw mousedown event for the entire grid.
51094 * @param {Roo.EventObject} e
51096 "mousedown" : true,
51099 * The raw mouseup event for the entire grid.
51100 * @param {Roo.EventObject} e
51105 * The raw mouseover event for the entire grid.
51106 * @param {Roo.EventObject} e
51108 "mouseover" : true,
51111 * The raw mouseout event for the entire grid.
51112 * @param {Roo.EventObject} e
51117 * The raw keypress event for the entire grid.
51118 * @param {Roo.EventObject} e
51123 * The raw keydown event for the entire grid.
51124 * @param {Roo.EventObject} e
51132 * Fires when a cell is clicked
51133 * @param {Grid} this
51134 * @param {Number} rowIndex
51135 * @param {Number} columnIndex
51136 * @param {Roo.EventObject} e
51138 "cellclick" : true,
51140 * @event celldblclick
51141 * Fires when a cell is double clicked
51142 * @param {Grid} this
51143 * @param {Number} rowIndex
51144 * @param {Number} columnIndex
51145 * @param {Roo.EventObject} e
51147 "celldblclick" : true,
51150 * Fires when a row is clicked
51151 * @param {Grid} this
51152 * @param {Number} rowIndex
51153 * @param {Roo.EventObject} e
51157 * @event rowdblclick
51158 * Fires when a row is double clicked
51159 * @param {Grid} this
51160 * @param {Number} rowIndex
51161 * @param {Roo.EventObject} e
51163 "rowdblclick" : true,
51165 * @event headerclick
51166 * Fires when a header is clicked
51167 * @param {Grid} this
51168 * @param {Number} columnIndex
51169 * @param {Roo.EventObject} e
51171 "headerclick" : true,
51173 * @event headerdblclick
51174 * Fires when a header cell is double clicked
51175 * @param {Grid} this
51176 * @param {Number} columnIndex
51177 * @param {Roo.EventObject} e
51179 "headerdblclick" : true,
51181 * @event rowcontextmenu
51182 * Fires when a row is right clicked
51183 * @param {Grid} this
51184 * @param {Number} rowIndex
51185 * @param {Roo.EventObject} e
51187 "rowcontextmenu" : true,
51189 * @event cellcontextmenu
51190 * Fires when a cell is right clicked
51191 * @param {Grid} this
51192 * @param {Number} rowIndex
51193 * @param {Number} cellIndex
51194 * @param {Roo.EventObject} e
51196 "cellcontextmenu" : true,
51198 * @event headercontextmenu
51199 * Fires when a header is right clicked
51200 * @param {Grid} this
51201 * @param {Number} columnIndex
51202 * @param {Roo.EventObject} e
51204 "headercontextmenu" : true,
51206 * @event bodyscroll
51207 * Fires when the body element is scrolled
51208 * @param {Number} scrollLeft
51209 * @param {Number} scrollTop
51211 "bodyscroll" : true,
51213 * @event columnresize
51214 * Fires when the user resizes a column
51215 * @param {Number} columnIndex
51216 * @param {Number} newSize
51218 "columnresize" : true,
51220 * @event columnmove
51221 * Fires when the user moves a column
51222 * @param {Number} oldIndex
51223 * @param {Number} newIndex
51225 "columnmove" : true,
51228 * Fires when row(s) start being dragged
51229 * @param {Grid} this
51230 * @param {Roo.GridDD} dd The drag drop object
51231 * @param {event} e The raw browser event
51233 "startdrag" : true,
51236 * Fires when a drag operation is complete
51237 * @param {Grid} this
51238 * @param {Roo.GridDD} dd The drag drop object
51239 * @param {event} e The raw browser event
51244 * Fires when dragged row(s) are dropped on a valid DD target
51245 * @param {Grid} this
51246 * @param {Roo.GridDD} dd The drag drop object
51247 * @param {String} targetId The target drag drop object
51248 * @param {event} e The raw browser event
51253 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
51254 * @param {Grid} this
51255 * @param {Roo.GridDD} dd The drag drop object
51256 * @param {String} targetId The target drag drop object
51257 * @param {event} e The raw browser event
51262 * Fires when the dragged row(s) first cross another DD target while being dragged
51263 * @param {Grid} this
51264 * @param {Roo.GridDD} dd The drag drop object
51265 * @param {String} targetId The target drag drop object
51266 * @param {event} e The raw browser event
51268 "dragenter" : true,
51271 * Fires when the dragged row(s) leave another DD target while being dragged
51272 * @param {Grid} this
51273 * @param {Roo.GridDD} dd The drag drop object
51274 * @param {String} targetId The target drag drop object
51275 * @param {event} e The raw browser event
51280 * Fires when a row is rendered, so you can change add a style to it.
51281 * @param {GridView} gridview The grid view
51282 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
51288 * Fires when the grid is rendered
51289 * @param {Grid} grid
51294 Roo.grid.Grid.superclass.constructor.call(this);
51296 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
51299 * @cfg {String} ddGroup - drag drop group.
51303 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
51305 minColumnWidth : 25,
51308 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
51309 * <b>on initial render.</b> It is more efficient to explicitly size the columns
51310 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
51312 autoSizeColumns : false,
51315 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
51317 autoSizeHeaders : true,
51320 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
51322 monitorWindowResize : true,
51325 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
51326 * rows measured to get a columns size. Default is 0 (all rows).
51328 maxRowsToMeasure : 0,
51331 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
51333 trackMouseOver : true,
51336 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
51340 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
51342 enableDragDrop : false,
51345 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
51347 enableColumnMove : true,
51350 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
51352 enableColumnHide : true,
51355 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
51357 enableRowHeightSync : false,
51360 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
51365 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
51367 autoHeight : false,
51370 * @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.
51372 autoExpandColumn : false,
51375 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
51378 autoExpandMin : 50,
51381 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
51383 autoExpandMax : 1000,
51386 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
51391 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
51395 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
51405 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
51406 * of a fixed width. Default is false.
51409 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
51412 * Called once after all setup has been completed and the grid is ready to be rendered.
51413 * @return {Roo.grid.Grid} this
51415 render : function()
51417 var c = this.container;
51418 // try to detect autoHeight/width mode
51419 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
51420 this.autoHeight = true;
51422 var view = this.getView();
51425 c.on("click", this.onClick, this);
51426 c.on("dblclick", this.onDblClick, this);
51427 c.on("contextmenu", this.onContextMenu, this);
51428 c.on("keydown", this.onKeyDown, this);
51430 c.on("touchstart", this.onTouchStart, this);
51433 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
51435 this.getSelectionModel().init(this);
51440 this.loadMask = new Roo.LoadMask(this.container,
51441 Roo.apply({store:this.dataSource}, this.loadMask));
51445 if (this.toolbar && this.toolbar.xtype) {
51446 this.toolbar.container = this.getView().getHeaderPanel(true);
51447 this.toolbar = new Roo.Toolbar(this.toolbar);
51449 if (this.footer && this.footer.xtype) {
51450 this.footer.dataSource = this.getDataSource();
51451 this.footer.container = this.getView().getFooterPanel(true);
51452 this.footer = Roo.factory(this.footer, Roo);
51454 if (this.dropTarget && this.dropTarget.xtype) {
51455 delete this.dropTarget.xtype;
51456 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
51460 this.rendered = true;
51461 this.fireEvent('render', this);
51466 * Reconfigures the grid to use a different Store and Column Model.
51467 * The View will be bound to the new objects and refreshed.
51468 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
51469 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
51471 reconfigure : function(dataSource, colModel){
51473 this.loadMask.destroy();
51474 this.loadMask = new Roo.LoadMask(this.container,
51475 Roo.apply({store:dataSource}, this.loadMask));
51477 this.view.bind(dataSource, colModel);
51478 this.dataSource = dataSource;
51479 this.colModel = colModel;
51480 this.view.refresh(true);
51484 onKeyDown : function(e){
51485 this.fireEvent("keydown", e);
51489 * Destroy this grid.
51490 * @param {Boolean} removeEl True to remove the element
51492 destroy : function(removeEl, keepListeners){
51494 this.loadMask.destroy();
51496 var c = this.container;
51497 c.removeAllListeners();
51498 this.view.destroy();
51499 this.colModel.purgeListeners();
51500 if(!keepListeners){
51501 this.purgeListeners();
51504 if(removeEl === true){
51510 processEvent : function(name, e){
51511 // does this fire select???
51512 Roo.log('grid:processEvent ' + name);
51514 if (name != 'touchstart' ) {
51515 this.fireEvent(name, e);
51518 var t = e.getTarget();
51520 var header = v.findHeaderIndex(t);
51521 if(header !== false){
51522 this.fireEvent("header" + (name == 'touchstart' ? 'click' : name), this, header, e);
51524 var row = v.findRowIndex(t);
51525 var cell = v.findCellIndex(t);
51526 if (name == 'touchstart') {
51527 // first touch is always a click.
51528 // hopefull this happens after selection is updated.?
51531 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
51532 var cs = this.selModel.getSelectedCell();
51533 if (row == cs[0] && cell == cs[1]){
51537 if (typeof(this.selModel.getSelections) != 'undefined') {
51538 var cs = this.selModel.getSelections();
51539 var ds = this.dataSource;
51540 if (cs.length == 1 && ds.getAt(row) == cs[0]){
51551 this.fireEvent("row" + name, this, row, e);
51552 if(cell !== false){
51553 this.fireEvent("cell" + name, this, row, cell, e);
51560 onClick : function(e){
51561 this.processEvent("click", e);
51564 onTouchStart : function(e){
51565 this.processEvent("touchstart", e);
51569 onContextMenu : function(e, t){
51570 this.processEvent("contextmenu", e);
51574 onDblClick : function(e){
51575 this.processEvent("dblclick", e);
51579 walkCells : function(row, col, step, fn, scope){
51580 var cm = this.colModel, clen = cm.getColumnCount();
51581 var ds = this.dataSource, rlen = ds.getCount(), first = true;
51593 if(fn.call(scope || this, row, col, cm) === true){
51611 if(fn.call(scope || this, row, col, cm) === true){
51623 getSelections : function(){
51624 return this.selModel.getSelections();
51628 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
51629 * but if manual update is required this method will initiate it.
51631 autoSize : function(){
51633 this.view.layout();
51634 if(this.view.adjustForScroll){
51635 this.view.adjustForScroll();
51641 * Returns the grid's underlying element.
51642 * @return {Element} The element
51644 getGridEl : function(){
51645 return this.container;
51648 // private for compatibility, overridden by editor grid
51649 stopEditing : function(){},
51652 * Returns the grid's SelectionModel.
51653 * @return {SelectionModel}
51655 getSelectionModel : function(){
51656 if(!this.selModel){
51657 this.selModel = new Roo.grid.RowSelectionModel();
51659 return this.selModel;
51663 * Returns the grid's DataSource.
51664 * @return {DataSource}
51666 getDataSource : function(){
51667 return this.dataSource;
51671 * Returns the grid's ColumnModel.
51672 * @return {ColumnModel}
51674 getColumnModel : function(){
51675 return this.colModel;
51679 * Returns the grid's GridView object.
51680 * @return {GridView}
51682 getView : function(){
51684 this.view = new Roo.grid.GridView(this.viewConfig);
51689 * Called to get grid's drag proxy text, by default returns this.ddText.
51692 getDragDropText : function(){
51693 var count = this.selModel.getCount();
51694 return String.format(this.ddText, count, count == 1 ? '' : 's');
51698 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
51699 * %0 is replaced with the number of selected rows.
51702 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
51704 * Ext JS Library 1.1.1
51705 * Copyright(c) 2006-2007, Ext JS, LLC.
51707 * Originally Released Under LGPL - original licence link has changed is not relivant.
51710 * <script type="text/javascript">
51713 Roo.grid.AbstractGridView = function(){
51717 "beforerowremoved" : true,
51718 "beforerowsinserted" : true,
51719 "beforerefresh" : true,
51720 "rowremoved" : true,
51721 "rowsinserted" : true,
51722 "rowupdated" : true,
51725 Roo.grid.AbstractGridView.superclass.constructor.call(this);
51728 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
51729 rowClass : "x-grid-row",
51730 cellClass : "x-grid-cell",
51731 tdClass : "x-grid-td",
51732 hdClass : "x-grid-hd",
51733 splitClass : "x-grid-hd-split",
51735 init: function(grid){
51737 var cid = this.grid.getGridEl().id;
51738 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
51739 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
51740 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
51741 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
51744 getColumnRenderers : function(){
51745 var renderers = [];
51746 var cm = this.grid.colModel;
51747 var colCount = cm.getColumnCount();
51748 for(var i = 0; i < colCount; i++){
51749 renderers[i] = cm.getRenderer(i);
51754 getColumnIds : function(){
51756 var cm = this.grid.colModel;
51757 var colCount = cm.getColumnCount();
51758 for(var i = 0; i < colCount; i++){
51759 ids[i] = cm.getColumnId(i);
51764 getDataIndexes : function(){
51765 if(!this.indexMap){
51766 this.indexMap = this.buildIndexMap();
51768 return this.indexMap.colToData;
51771 getColumnIndexByDataIndex : function(dataIndex){
51772 if(!this.indexMap){
51773 this.indexMap = this.buildIndexMap();
51775 return this.indexMap.dataToCol[dataIndex];
51779 * Set a css style for a column dynamically.
51780 * @param {Number} colIndex The index of the column
51781 * @param {String} name The css property name
51782 * @param {String} value The css value
51784 setCSSStyle : function(colIndex, name, value){
51785 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
51786 Roo.util.CSS.updateRule(selector, name, value);
51789 generateRules : function(cm){
51790 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
51791 Roo.util.CSS.removeStyleSheet(rulesId);
51792 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51793 var cid = cm.getColumnId(i);
51794 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
51795 this.tdSelector, cid, " {\n}\n",
51796 this.hdSelector, cid, " {\n}\n",
51797 this.splitSelector, cid, " {\n}\n");
51799 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
51803 * Ext JS Library 1.1.1
51804 * Copyright(c) 2006-2007, Ext JS, LLC.
51806 * Originally Released Under LGPL - original licence link has changed is not relivant.
51809 * <script type="text/javascript">
51813 // This is a support class used internally by the Grid components
51814 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
51816 this.view = grid.getView();
51817 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
51818 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
51820 this.setHandleElId(Roo.id(hd));
51821 this.setOuterHandleElId(Roo.id(hd2));
51823 this.scroll = false;
51825 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
51827 getDragData : function(e){
51828 var t = Roo.lib.Event.getTarget(e);
51829 var h = this.view.findHeaderCell(t);
51831 return {ddel: h.firstChild, header:h};
51836 onInitDrag : function(e){
51837 this.view.headersDisabled = true;
51838 var clone = this.dragData.ddel.cloneNode(true);
51839 clone.id = Roo.id();
51840 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
51841 this.proxy.update(clone);
51845 afterValidDrop : function(){
51847 setTimeout(function(){
51848 v.headersDisabled = false;
51852 afterInvalidDrop : function(){
51854 setTimeout(function(){
51855 v.headersDisabled = false;
51861 * Ext JS Library 1.1.1
51862 * Copyright(c) 2006-2007, Ext JS, LLC.
51864 * Originally Released Under LGPL - original licence link has changed is not relivant.
51867 * <script type="text/javascript">
51870 // This is a support class used internally by the Grid components
51871 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
51873 this.view = grid.getView();
51874 // split the proxies so they don't interfere with mouse events
51875 this.proxyTop = Roo.DomHelper.append(document.body, {
51876 cls:"col-move-top", html:" "
51878 this.proxyBottom = Roo.DomHelper.append(document.body, {
51879 cls:"col-move-bottom", html:" "
51881 this.proxyTop.hide = this.proxyBottom.hide = function(){
51882 this.setLeftTop(-100,-100);
51883 this.setStyle("visibility", "hidden");
51885 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
51886 // temporarily disabled
51887 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
51888 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
51890 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
51891 proxyOffsets : [-4, -9],
51892 fly: Roo.Element.fly,
51894 getTargetFromEvent : function(e){
51895 var t = Roo.lib.Event.getTarget(e);
51896 var cindex = this.view.findCellIndex(t);
51897 if(cindex !== false){
51898 return this.view.getHeaderCell(cindex);
51903 nextVisible : function(h){
51904 var v = this.view, cm = this.grid.colModel;
51907 if(!cm.isHidden(v.getCellIndex(h))){
51915 prevVisible : function(h){
51916 var v = this.view, cm = this.grid.colModel;
51919 if(!cm.isHidden(v.getCellIndex(h))){
51927 positionIndicator : function(h, n, e){
51928 var x = Roo.lib.Event.getPageX(e);
51929 var r = Roo.lib.Dom.getRegion(n.firstChild);
51930 var px, pt, py = r.top + this.proxyOffsets[1];
51931 if((r.right - x) <= (r.right-r.left)/2){
51932 px = r.right+this.view.borderWidth;
51938 var oldIndex = this.view.getCellIndex(h);
51939 var newIndex = this.view.getCellIndex(n);
51941 if(this.grid.colModel.isFixed(newIndex)){
51945 var locked = this.grid.colModel.isLocked(newIndex);
51950 if(oldIndex < newIndex){
51953 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
51956 px += this.proxyOffsets[0];
51957 this.proxyTop.setLeftTop(px, py);
51958 this.proxyTop.show();
51959 if(!this.bottomOffset){
51960 this.bottomOffset = this.view.mainHd.getHeight();
51962 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
51963 this.proxyBottom.show();
51967 onNodeEnter : function(n, dd, e, data){
51968 if(data.header != n){
51969 this.positionIndicator(data.header, n, e);
51973 onNodeOver : function(n, dd, e, data){
51974 var result = false;
51975 if(data.header != n){
51976 result = this.positionIndicator(data.header, n, e);
51979 this.proxyTop.hide();
51980 this.proxyBottom.hide();
51982 return result ? this.dropAllowed : this.dropNotAllowed;
51985 onNodeOut : function(n, dd, e, data){
51986 this.proxyTop.hide();
51987 this.proxyBottom.hide();
51990 onNodeDrop : function(n, dd, e, data){
51991 var h = data.header;
51993 var cm = this.grid.colModel;
51994 var x = Roo.lib.Event.getPageX(e);
51995 var r = Roo.lib.Dom.getRegion(n.firstChild);
51996 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
51997 var oldIndex = this.view.getCellIndex(h);
51998 var newIndex = this.view.getCellIndex(n);
51999 var locked = cm.isLocked(newIndex);
52003 if(oldIndex < newIndex){
52006 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
52009 cm.setLocked(oldIndex, locked, true);
52010 cm.moveColumn(oldIndex, newIndex);
52011 this.grid.fireEvent("columnmove", oldIndex, newIndex);
52019 * Ext JS Library 1.1.1
52020 * Copyright(c) 2006-2007, Ext JS, LLC.
52022 * Originally Released Under LGPL - original licence link has changed is not relivant.
52025 * <script type="text/javascript">
52029 * @class Roo.grid.GridView
52030 * @extends Roo.util.Observable
52033 * @param {Object} config
52035 Roo.grid.GridView = function(config){
52036 Roo.grid.GridView.superclass.constructor.call(this);
52039 Roo.apply(this, config);
52042 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
52044 unselectable : 'unselectable="on"',
52045 unselectableCls : 'x-unselectable',
52048 rowClass : "x-grid-row",
52050 cellClass : "x-grid-col",
52052 tdClass : "x-grid-td",
52054 hdClass : "x-grid-hd",
52056 splitClass : "x-grid-split",
52058 sortClasses : ["sort-asc", "sort-desc"],
52060 enableMoveAnim : false,
52064 dh : Roo.DomHelper,
52066 fly : Roo.Element.fly,
52068 css : Roo.util.CSS,
52074 scrollIncrement : 22,
52076 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
52078 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
52080 bind : function(ds, cm){
52082 this.ds.un("load", this.onLoad, this);
52083 this.ds.un("datachanged", this.onDataChange, this);
52084 this.ds.un("add", this.onAdd, this);
52085 this.ds.un("remove", this.onRemove, this);
52086 this.ds.un("update", this.onUpdate, this);
52087 this.ds.un("clear", this.onClear, this);
52090 ds.on("load", this.onLoad, this);
52091 ds.on("datachanged", this.onDataChange, this);
52092 ds.on("add", this.onAdd, this);
52093 ds.on("remove", this.onRemove, this);
52094 ds.on("update", this.onUpdate, this);
52095 ds.on("clear", this.onClear, this);
52100 this.cm.un("widthchange", this.onColWidthChange, this);
52101 this.cm.un("headerchange", this.onHeaderChange, this);
52102 this.cm.un("hiddenchange", this.onHiddenChange, this);
52103 this.cm.un("columnmoved", this.onColumnMove, this);
52104 this.cm.un("columnlockchange", this.onColumnLock, this);
52107 this.generateRules(cm);
52108 cm.on("widthchange", this.onColWidthChange, this);
52109 cm.on("headerchange", this.onHeaderChange, this);
52110 cm.on("hiddenchange", this.onHiddenChange, this);
52111 cm.on("columnmoved", this.onColumnMove, this);
52112 cm.on("columnlockchange", this.onColumnLock, this);
52117 init: function(grid){
52118 Roo.grid.GridView.superclass.init.call(this, grid);
52120 this.bind(grid.dataSource, grid.colModel);
52122 grid.on("headerclick", this.handleHeaderClick, this);
52124 if(grid.trackMouseOver){
52125 grid.on("mouseover", this.onRowOver, this);
52126 grid.on("mouseout", this.onRowOut, this);
52128 grid.cancelTextSelection = function(){};
52129 this.gridId = grid.id;
52131 var tpls = this.templates || {};
52134 tpls.master = new Roo.Template(
52135 '<div class="x-grid" hidefocus="true">',
52136 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
52137 '<div class="x-grid-topbar"></div>',
52138 '<div class="x-grid-scroller"><div></div></div>',
52139 '<div class="x-grid-locked">',
52140 '<div class="x-grid-header">{lockedHeader}</div>',
52141 '<div class="x-grid-body">{lockedBody}</div>',
52143 '<div class="x-grid-viewport">',
52144 '<div class="x-grid-header">{header}</div>',
52145 '<div class="x-grid-body">{body}</div>',
52147 '<div class="x-grid-bottombar"></div>',
52149 '<div class="x-grid-resize-proxy"> </div>',
52152 tpls.master.disableformats = true;
52156 tpls.header = new Roo.Template(
52157 '<table border="0" cellspacing="0" cellpadding="0">',
52158 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
52161 tpls.header.disableformats = true;
52163 tpls.header.compile();
52166 tpls.hcell = new Roo.Template(
52167 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
52168 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
52171 tpls.hcell.disableFormats = true;
52173 tpls.hcell.compile();
52176 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
52177 this.unselectableCls + '" ' + this.unselectable +'> </div>');
52178 tpls.hsplit.disableFormats = true;
52180 tpls.hsplit.compile();
52183 tpls.body = new Roo.Template(
52184 '<table border="0" cellspacing="0" cellpadding="0">',
52185 "<tbody>{rows}</tbody>",
52188 tpls.body.disableFormats = true;
52190 tpls.body.compile();
52193 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
52194 tpls.row.disableFormats = true;
52196 tpls.row.compile();
52199 tpls.cell = new Roo.Template(
52200 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
52201 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
52202 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
52205 tpls.cell.disableFormats = true;
52207 tpls.cell.compile();
52209 this.templates = tpls;
52212 // remap these for backwards compat
52213 onColWidthChange : function(){
52214 this.updateColumns.apply(this, arguments);
52216 onHeaderChange : function(){
52217 this.updateHeaders.apply(this, arguments);
52219 onHiddenChange : function(){
52220 this.handleHiddenChange.apply(this, arguments);
52222 onColumnMove : function(){
52223 this.handleColumnMove.apply(this, arguments);
52225 onColumnLock : function(){
52226 this.handleLockChange.apply(this, arguments);
52229 onDataChange : function(){
52231 this.updateHeaderSortState();
52234 onClear : function(){
52238 onUpdate : function(ds, record){
52239 this.refreshRow(record);
52242 refreshRow : function(record){
52243 var ds = this.ds, index;
52244 if(typeof record == 'number'){
52246 record = ds.getAt(index);
52248 index = ds.indexOf(record);
52250 this.insertRows(ds, index, index, true);
52251 this.onRemove(ds, record, index+1, true);
52252 this.syncRowHeights(index, index);
52254 this.fireEvent("rowupdated", this, index, record);
52257 onAdd : function(ds, records, index){
52258 this.insertRows(ds, index, index + (records.length-1));
52261 onRemove : function(ds, record, index, isUpdate){
52262 if(isUpdate !== true){
52263 this.fireEvent("beforerowremoved", this, index, record);
52265 var bt = this.getBodyTable(), lt = this.getLockedTable();
52266 if(bt.rows[index]){
52267 bt.firstChild.removeChild(bt.rows[index]);
52269 if(lt.rows[index]){
52270 lt.firstChild.removeChild(lt.rows[index]);
52272 if(isUpdate !== true){
52273 this.stripeRows(index);
52274 this.syncRowHeights(index, index);
52276 this.fireEvent("rowremoved", this, index, record);
52280 onLoad : function(){
52281 this.scrollToTop();
52285 * Scrolls the grid to the top
52287 scrollToTop : function(){
52289 this.scroller.dom.scrollTop = 0;
52295 * Gets a panel in the header of the grid that can be used for toolbars etc.
52296 * After modifying the contents of this panel a call to grid.autoSize() may be
52297 * required to register any changes in size.
52298 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
52299 * @return Roo.Element
52301 getHeaderPanel : function(doShow){
52303 this.headerPanel.show();
52305 return this.headerPanel;
52309 * Gets a panel in the footer of the grid that can be used for toolbars etc.
52310 * After modifying the contents of this panel a call to grid.autoSize() may be
52311 * required to register any changes in size.
52312 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
52313 * @return Roo.Element
52315 getFooterPanel : function(doShow){
52317 this.footerPanel.show();
52319 return this.footerPanel;
52322 initElements : function(){
52323 var E = Roo.Element;
52324 var el = this.grid.getGridEl().dom.firstChild;
52325 var cs = el.childNodes;
52327 this.el = new E(el);
52329 this.focusEl = new E(el.firstChild);
52330 this.focusEl.swallowEvent("click", true);
52332 this.headerPanel = new E(cs[1]);
52333 this.headerPanel.enableDisplayMode("block");
52335 this.scroller = new E(cs[2]);
52336 this.scrollSizer = new E(this.scroller.dom.firstChild);
52338 this.lockedWrap = new E(cs[3]);
52339 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
52340 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
52342 this.mainWrap = new E(cs[4]);
52343 this.mainHd = new E(this.mainWrap.dom.firstChild);
52344 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
52346 this.footerPanel = new E(cs[5]);
52347 this.footerPanel.enableDisplayMode("block");
52349 this.resizeProxy = new E(cs[6]);
52351 this.headerSelector = String.format(
52352 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
52353 this.lockedHd.id, this.mainHd.id
52356 this.splitterSelector = String.format(
52357 '#{0} div.x-grid-split, #{1} div.x-grid-split',
52358 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
52361 idToCssName : function(s)
52363 return s.replace(/[^a-z0-9]+/ig, '-');
52366 getHeaderCell : function(index){
52367 return Roo.DomQuery.select(this.headerSelector)[index];
52370 getHeaderCellMeasure : function(index){
52371 return this.getHeaderCell(index).firstChild;
52374 getHeaderCellText : function(index){
52375 return this.getHeaderCell(index).firstChild.firstChild;
52378 getLockedTable : function(){
52379 return this.lockedBody.dom.firstChild;
52382 getBodyTable : function(){
52383 return this.mainBody.dom.firstChild;
52386 getLockedRow : function(index){
52387 return this.getLockedTable().rows[index];
52390 getRow : function(index){
52391 return this.getBodyTable().rows[index];
52394 getRowComposite : function(index){
52396 this.rowEl = new Roo.CompositeElementLite();
52398 var els = [], lrow, mrow;
52399 if(lrow = this.getLockedRow(index)){
52402 if(mrow = this.getRow(index)){
52405 this.rowEl.elements = els;
52409 * Gets the 'td' of the cell
52411 * @param {Integer} rowIndex row to select
52412 * @param {Integer} colIndex column to select
52416 getCell : function(rowIndex, colIndex){
52417 var locked = this.cm.getLockedCount();
52419 if(colIndex < locked){
52420 source = this.lockedBody.dom.firstChild;
52422 source = this.mainBody.dom.firstChild;
52423 colIndex -= locked;
52425 return source.rows[rowIndex].childNodes[colIndex];
52428 getCellText : function(rowIndex, colIndex){
52429 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
52432 getCellBox : function(cell){
52433 var b = this.fly(cell).getBox();
52434 if(Roo.isOpera){ // opera fails to report the Y
52435 b.y = cell.offsetTop + this.mainBody.getY();
52440 getCellIndex : function(cell){
52441 var id = String(cell.className).match(this.cellRE);
52443 return parseInt(id[1], 10);
52448 findHeaderIndex : function(n){
52449 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
52450 return r ? this.getCellIndex(r) : false;
52453 findHeaderCell : function(n){
52454 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
52455 return r ? r : false;
52458 findRowIndex : function(n){
52462 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
52463 return r ? r.rowIndex : false;
52466 findCellIndex : function(node){
52467 var stop = this.el.dom;
52468 while(node && node != stop){
52469 if(this.findRE.test(node.className)){
52470 return this.getCellIndex(node);
52472 node = node.parentNode;
52477 getColumnId : function(index){
52478 return this.cm.getColumnId(index);
52481 getSplitters : function()
52483 if(this.splitterSelector){
52484 return Roo.DomQuery.select(this.splitterSelector);
52490 getSplitter : function(index){
52491 return this.getSplitters()[index];
52494 onRowOver : function(e, t){
52496 if((row = this.findRowIndex(t)) !== false){
52497 this.getRowComposite(row).addClass("x-grid-row-over");
52501 onRowOut : function(e, t){
52503 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
52504 this.getRowComposite(row).removeClass("x-grid-row-over");
52508 renderHeaders : function(){
52510 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
52511 var cb = [], lb = [], sb = [], lsb = [], p = {};
52512 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52513 p.cellId = "x-grid-hd-0-" + i;
52514 p.splitId = "x-grid-csplit-0-" + i;
52515 p.id = cm.getColumnId(i);
52516 p.title = cm.getColumnTooltip(i) || "";
52517 p.value = cm.getColumnHeader(i) || "";
52518 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
52519 if(!cm.isLocked(i)){
52520 cb[cb.length] = ct.apply(p);
52521 sb[sb.length] = st.apply(p);
52523 lb[lb.length] = ct.apply(p);
52524 lsb[lsb.length] = st.apply(p);
52527 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
52528 ht.apply({cells: cb.join(""), splits:sb.join("")})];
52531 updateHeaders : function(){
52532 var html = this.renderHeaders();
52533 this.lockedHd.update(html[0]);
52534 this.mainHd.update(html[1]);
52538 * Focuses the specified row.
52539 * @param {Number} row The row index
52541 focusRow : function(row)
52543 //Roo.log('GridView.focusRow');
52544 var x = this.scroller.dom.scrollLeft;
52545 this.focusCell(row, 0, false);
52546 this.scroller.dom.scrollLeft = x;
52550 * Focuses the specified cell.
52551 * @param {Number} row The row index
52552 * @param {Number} col The column index
52553 * @param {Boolean} hscroll false to disable horizontal scrolling
52555 focusCell : function(row, col, hscroll)
52557 //Roo.log('GridView.focusCell');
52558 var el = this.ensureVisible(row, col, hscroll);
52559 this.focusEl.alignTo(el, "tl-tl");
52561 this.focusEl.focus();
52563 this.focusEl.focus.defer(1, this.focusEl);
52568 * Scrolls the specified cell into view
52569 * @param {Number} row The row index
52570 * @param {Number} col The column index
52571 * @param {Boolean} hscroll false to disable horizontal scrolling
52573 ensureVisible : function(row, col, hscroll)
52575 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
52576 //return null; //disable for testing.
52577 if(typeof row != "number"){
52578 row = row.rowIndex;
52580 if(row < 0 && row >= this.ds.getCount()){
52583 col = (col !== undefined ? col : 0);
52584 var cm = this.grid.colModel;
52585 while(cm.isHidden(col)){
52589 var el = this.getCell(row, col);
52593 var c = this.scroller.dom;
52595 var ctop = parseInt(el.offsetTop, 10);
52596 var cleft = parseInt(el.offsetLeft, 10);
52597 var cbot = ctop + el.offsetHeight;
52598 var cright = cleft + el.offsetWidth;
52600 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
52601 var stop = parseInt(c.scrollTop, 10);
52602 var sleft = parseInt(c.scrollLeft, 10);
52603 var sbot = stop + ch;
52604 var sright = sleft + c.clientWidth;
52606 Roo.log('GridView.ensureVisible:' +
52608 ' c.clientHeight:' + c.clientHeight +
52609 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
52617 c.scrollTop = ctop;
52618 //Roo.log("set scrolltop to ctop DISABLE?");
52619 }else if(cbot > sbot){
52620 //Roo.log("set scrolltop to cbot-ch");
52621 c.scrollTop = cbot-ch;
52624 if(hscroll !== false){
52626 c.scrollLeft = cleft;
52627 }else if(cright > sright){
52628 c.scrollLeft = cright-c.clientWidth;
52635 updateColumns : function(){
52636 this.grid.stopEditing();
52637 var cm = this.grid.colModel, colIds = this.getColumnIds();
52638 //var totalWidth = cm.getTotalWidth();
52640 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52641 //if(cm.isHidden(i)) continue;
52642 var w = cm.getColumnWidth(i);
52643 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
52644 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
52646 this.updateSplitters();
52649 generateRules : function(cm){
52650 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
52651 Roo.util.CSS.removeStyleSheet(rulesId);
52652 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52653 var cid = cm.getColumnId(i);
52655 if(cm.config[i].align){
52656 align = 'text-align:'+cm.config[i].align+';';
52659 if(cm.isHidden(i)){
52660 hidden = 'display:none;';
52662 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
52664 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
52665 this.hdSelector, cid, " {\n", align, width, "}\n",
52666 this.tdSelector, cid, " {\n",hidden,"\n}\n",
52667 this.splitSelector, cid, " {\n", hidden , "\n}\n");
52669 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52672 updateSplitters : function(){
52673 var cm = this.cm, s = this.getSplitters();
52674 if(s){ // splitters not created yet
52675 var pos = 0, locked = true;
52676 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52677 if(cm.isHidden(i)) continue;
52678 var w = cm.getColumnWidth(i); // make sure it's a number
52679 if(!cm.isLocked(i) && locked){
52684 s[i].style.left = (pos-this.splitOffset) + "px";
52689 handleHiddenChange : function(colModel, colIndex, hidden){
52691 this.hideColumn(colIndex);
52693 this.unhideColumn(colIndex);
52697 hideColumn : function(colIndex){
52698 var cid = this.getColumnId(colIndex);
52699 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
52700 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
52702 this.updateHeaders();
52704 this.updateSplitters();
52708 unhideColumn : function(colIndex){
52709 var cid = this.getColumnId(colIndex);
52710 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
52711 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
52714 this.updateHeaders();
52716 this.updateSplitters();
52720 insertRows : function(dm, firstRow, lastRow, isUpdate){
52721 if(firstRow == 0 && lastRow == dm.getCount()-1){
52725 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
52727 var s = this.getScrollState();
52728 var markup = this.renderRows(firstRow, lastRow);
52729 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
52730 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
52731 this.restoreScroll(s);
52733 this.fireEvent("rowsinserted", this, firstRow, lastRow);
52734 this.syncRowHeights(firstRow, lastRow);
52735 this.stripeRows(firstRow);
52741 bufferRows : function(markup, target, index){
52742 var before = null, trows = target.rows, tbody = target.tBodies[0];
52743 if(index < trows.length){
52744 before = trows[index];
52746 var b = document.createElement("div");
52747 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
52748 var rows = b.firstChild.rows;
52749 for(var i = 0, len = rows.length; i < len; i++){
52751 tbody.insertBefore(rows[0], before);
52753 tbody.appendChild(rows[0]);
52760 deleteRows : function(dm, firstRow, lastRow){
52761 if(dm.getRowCount()<1){
52762 this.fireEvent("beforerefresh", this);
52763 this.mainBody.update("");
52764 this.lockedBody.update("");
52765 this.fireEvent("refresh", this);
52767 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
52768 var bt = this.getBodyTable();
52769 var tbody = bt.firstChild;
52770 var rows = bt.rows;
52771 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
52772 tbody.removeChild(rows[firstRow]);
52774 this.stripeRows(firstRow);
52775 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
52779 updateRows : function(dataSource, firstRow, lastRow){
52780 var s = this.getScrollState();
52782 this.restoreScroll(s);
52785 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
52789 this.updateHeaderSortState();
52792 getScrollState : function(){
52794 var sb = this.scroller.dom;
52795 return {left: sb.scrollLeft, top: sb.scrollTop};
52798 stripeRows : function(startRow){
52799 if(!this.grid.stripeRows || this.ds.getCount() < 1){
52802 startRow = startRow || 0;
52803 var rows = this.getBodyTable().rows;
52804 var lrows = this.getLockedTable().rows;
52805 var cls = ' x-grid-row-alt ';
52806 for(var i = startRow, len = rows.length; i < len; i++){
52807 var row = rows[i], lrow = lrows[i];
52808 var isAlt = ((i+1) % 2 == 0);
52809 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
52810 if(isAlt == hasAlt){
52814 row.className += " x-grid-row-alt";
52816 row.className = row.className.replace("x-grid-row-alt", "");
52819 lrow.className = row.className;
52824 restoreScroll : function(state){
52825 //Roo.log('GridView.restoreScroll');
52826 var sb = this.scroller.dom;
52827 sb.scrollLeft = state.left;
52828 sb.scrollTop = state.top;
52832 syncScroll : function(){
52833 //Roo.log('GridView.syncScroll');
52834 var sb = this.scroller.dom;
52835 var sh = this.mainHd.dom;
52836 var bs = this.mainBody.dom;
52837 var lv = this.lockedBody.dom;
52838 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
52839 lv.scrollTop = bs.scrollTop = sb.scrollTop;
52842 handleScroll : function(e){
52844 var sb = this.scroller.dom;
52845 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
52849 handleWheel : function(e){
52850 var d = e.getWheelDelta();
52851 this.scroller.dom.scrollTop -= d*22;
52852 // set this here to prevent jumpy scrolling on large tables
52853 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
52857 renderRows : function(startRow, endRow){
52858 // pull in all the crap needed to render rows
52859 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
52860 var colCount = cm.getColumnCount();
52862 if(ds.getCount() < 1){
52866 // build a map for all the columns
52868 for(var i = 0; i < colCount; i++){
52869 var name = cm.getDataIndex(i);
52871 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
52872 renderer : cm.getRenderer(i),
52873 id : cm.getColumnId(i),
52874 locked : cm.isLocked(i)
52878 startRow = startRow || 0;
52879 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
52881 // records to render
52882 var rs = ds.getRange(startRow, endRow);
52884 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
52887 // As much as I hate to duplicate code, this was branched because FireFox really hates
52888 // [].join("") on strings. The performance difference was substantial enough to
52889 // branch this function
52890 doRender : Roo.isGecko ?
52891 function(cs, rs, ds, startRow, colCount, stripe){
52892 var ts = this.templates, ct = ts.cell, rt = ts.row;
52894 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
52896 var hasListener = this.grid.hasListener('rowclass');
52898 for(var j = 0, len = rs.length; j < len; j++){
52899 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
52900 for(var i = 0; i < colCount; i++){
52902 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
52904 p.css = p.attr = "";
52905 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
52906 if(p.value == undefined || p.value === "") p.value = " ";
52907 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
52908 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
52910 var markup = ct.apply(p);
52918 if(stripe && ((rowIndex+1) % 2 == 0)){
52919 alt.push("x-grid-row-alt")
52922 alt.push( " x-grid-dirty-row");
52925 if(this.getRowClass){
52926 alt.push(this.getRowClass(r, rowIndex));
52932 rowIndex : rowIndex,
52935 this.grid.fireEvent('rowclass', this, rowcfg);
52936 alt.push(rowcfg.rowClass);
52938 rp.alt = alt.join(" ");
52939 lbuf+= rt.apply(rp);
52941 buf+= rt.apply(rp);
52943 return [lbuf, buf];
52945 function(cs, rs, ds, startRow, colCount, stripe){
52946 var ts = this.templates, ct = ts.cell, rt = ts.row;
52948 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
52949 var hasListener = this.grid.hasListener('rowclass');
52952 for(var j = 0, len = rs.length; j < len; j++){
52953 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
52954 for(var i = 0; i < colCount; i++){
52956 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
52958 p.css = p.attr = "";
52959 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
52960 if(p.value == undefined || p.value === "") p.value = " ";
52961 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
52962 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
52965 var markup = ct.apply(p);
52967 cb[cb.length] = markup;
52969 lcb[lcb.length] = markup;
52973 if(stripe && ((rowIndex+1) % 2 == 0)){
52974 alt.push( "x-grid-row-alt");
52977 alt.push(" x-grid-dirty-row");
52980 if(this.getRowClass){
52981 alt.push( this.getRowClass(r, rowIndex));
52987 rowIndex : rowIndex,
52990 this.grid.fireEvent('rowclass', this, rowcfg);
52991 alt.push(rowcfg.rowClass);
52993 rp.alt = alt.join(" ");
52994 rp.cells = lcb.join("");
52995 lbuf[lbuf.length] = rt.apply(rp);
52996 rp.cells = cb.join("");
52997 buf[buf.length] = rt.apply(rp);
52999 return [lbuf.join(""), buf.join("")];
53002 renderBody : function(){
53003 var markup = this.renderRows();
53004 var bt = this.templates.body;
53005 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
53009 * Refreshes the grid
53010 * @param {Boolean} headersToo
53012 refresh : function(headersToo){
53013 this.fireEvent("beforerefresh", this);
53014 this.grid.stopEditing();
53015 var result = this.renderBody();
53016 this.lockedBody.update(result[0]);
53017 this.mainBody.update(result[1]);
53018 if(headersToo === true){
53019 this.updateHeaders();
53020 this.updateColumns();
53021 this.updateSplitters();
53022 this.updateHeaderSortState();
53024 this.syncRowHeights();
53026 this.fireEvent("refresh", this);
53029 handleColumnMove : function(cm, oldIndex, newIndex){
53030 this.indexMap = null;
53031 var s = this.getScrollState();
53032 this.refresh(true);
53033 this.restoreScroll(s);
53034 this.afterMove(newIndex);
53037 afterMove : function(colIndex){
53038 if(this.enableMoveAnim && Roo.enableFx){
53039 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
53041 // if multisort - fix sortOrder, and reload..
53042 if (this.grid.dataSource.multiSort) {
53043 // the we can call sort again..
53044 var dm = this.grid.dataSource;
53045 var cm = this.grid.colModel;
53047 for(var i = 0; i < cm.config.length; i++ ) {
53049 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
53050 continue; // dont' bother, it's not in sort list or being set.
53053 so.push(cm.config[i].dataIndex);
53056 dm.load(dm.lastOptions);
53063 updateCell : function(dm, rowIndex, dataIndex){
53064 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
53065 if(typeof colIndex == "undefined"){ // not present in grid
53068 var cm = this.grid.colModel;
53069 var cell = this.getCell(rowIndex, colIndex);
53070 var cellText = this.getCellText(rowIndex, colIndex);
53073 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
53074 id : cm.getColumnId(colIndex),
53075 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
53077 var renderer = cm.getRenderer(colIndex);
53078 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
53079 if(typeof val == "undefined" || val === "") val = " ";
53080 cellText.innerHTML = val;
53081 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
53082 this.syncRowHeights(rowIndex, rowIndex);
53085 calcColumnWidth : function(colIndex, maxRowsToMeasure){
53087 if(this.grid.autoSizeHeaders){
53088 var h = this.getHeaderCellMeasure(colIndex);
53089 maxWidth = Math.max(maxWidth, h.scrollWidth);
53092 if(this.cm.isLocked(colIndex)){
53093 tb = this.getLockedTable();
53096 tb = this.getBodyTable();
53097 index = colIndex - this.cm.getLockedCount();
53100 var rows = tb.rows;
53101 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
53102 for(var i = 0; i < stopIndex; i++){
53103 var cell = rows[i].childNodes[index].firstChild;
53104 maxWidth = Math.max(maxWidth, cell.scrollWidth);
53107 return maxWidth + /*margin for error in IE*/ 5;
53110 * Autofit a column to its content.
53111 * @param {Number} colIndex
53112 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
53114 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
53115 if(this.cm.isHidden(colIndex)){
53116 return; // can't calc a hidden column
53119 var cid = this.cm.getColumnId(colIndex);
53120 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
53121 if(this.grid.autoSizeHeaders){
53122 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
53125 var newWidth = this.calcColumnWidth(colIndex);
53126 this.cm.setColumnWidth(colIndex,
53127 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
53128 if(!suppressEvent){
53129 this.grid.fireEvent("columnresize", colIndex, newWidth);
53134 * Autofits all columns to their content and then expands to fit any extra space in the grid
53136 autoSizeColumns : function(){
53137 var cm = this.grid.colModel;
53138 var colCount = cm.getColumnCount();
53139 for(var i = 0; i < colCount; i++){
53140 this.autoSizeColumn(i, true, true);
53142 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
53145 this.updateColumns();
53151 * Autofits all columns to the grid's width proportionate with their current size
53152 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
53154 fitColumns : function(reserveScrollSpace){
53155 var cm = this.grid.colModel;
53156 var colCount = cm.getColumnCount();
53160 for (i = 0; i < colCount; i++){
53161 if(!cm.isHidden(i) && !cm.isFixed(i)){
53162 w = cm.getColumnWidth(i);
53168 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
53169 if(reserveScrollSpace){
53172 var frac = (avail - cm.getTotalWidth())/width;
53173 while (cols.length){
53176 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
53178 this.updateColumns();
53182 onRowSelect : function(rowIndex){
53183 var row = this.getRowComposite(rowIndex);
53184 row.addClass("x-grid-row-selected");
53187 onRowDeselect : function(rowIndex){
53188 var row = this.getRowComposite(rowIndex);
53189 row.removeClass("x-grid-row-selected");
53192 onCellSelect : function(row, col){
53193 var cell = this.getCell(row, col);
53195 Roo.fly(cell).addClass("x-grid-cell-selected");
53199 onCellDeselect : function(row, col){
53200 var cell = this.getCell(row, col);
53202 Roo.fly(cell).removeClass("x-grid-cell-selected");
53206 updateHeaderSortState : function(){
53208 // sort state can be single { field: xxx, direction : yyy}
53209 // or { xxx=>ASC , yyy : DESC ..... }
53212 if (!this.ds.multiSort) {
53213 var state = this.ds.getSortState();
53217 mstate[state.field] = state.direction;
53218 // FIXME... - this is not used here.. but might be elsewhere..
53219 this.sortState = state;
53222 mstate = this.ds.sortToggle;
53224 //remove existing sort classes..
53226 var sc = this.sortClasses;
53227 var hds = this.el.select(this.headerSelector).removeClass(sc);
53229 for(var f in mstate) {
53231 var sortColumn = this.cm.findColumnIndex(f);
53233 if(sortColumn != -1){
53234 var sortDir = mstate[f];
53235 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
53244 handleHeaderClick : function(g, index){
53245 if(this.headersDisabled){
53248 var dm = g.dataSource, cm = g.colModel;
53249 if(!cm.isSortable(index)){
53254 if (dm.multiSort) {
53255 // update the sortOrder
53257 for(var i = 0; i < cm.config.length; i++ ) {
53259 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
53260 continue; // dont' bother, it's not in sort list or being set.
53263 so.push(cm.config[i].dataIndex);
53269 dm.sort(cm.getDataIndex(index));
53273 destroy : function(){
53275 this.colMenu.removeAll();
53276 Roo.menu.MenuMgr.unregister(this.colMenu);
53277 this.colMenu.getEl().remove();
53278 delete this.colMenu;
53281 this.hmenu.removeAll();
53282 Roo.menu.MenuMgr.unregister(this.hmenu);
53283 this.hmenu.getEl().remove();
53286 if(this.grid.enableColumnMove){
53287 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53289 for(var dd in dds){
53290 if(!dds[dd].config.isTarget && dds[dd].dragElId){
53291 var elid = dds[dd].dragElId;
53293 Roo.get(elid).remove();
53294 } else if(dds[dd].config.isTarget){
53295 dds[dd].proxyTop.remove();
53296 dds[dd].proxyBottom.remove();
53299 if(Roo.dd.DDM.locationCache[dd]){
53300 delete Roo.dd.DDM.locationCache[dd];
53303 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53306 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
53307 this.bind(null, null);
53308 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
53311 handleLockChange : function(){
53312 this.refresh(true);
53315 onDenyColumnLock : function(){
53319 onDenyColumnHide : function(){
53323 handleHdMenuClick : function(item){
53324 var index = this.hdCtxIndex;
53325 var cm = this.cm, ds = this.ds;
53328 ds.sort(cm.getDataIndex(index), "ASC");
53331 ds.sort(cm.getDataIndex(index), "DESC");
53334 var lc = cm.getLockedCount();
53335 if(cm.getColumnCount(true) <= lc+1){
53336 this.onDenyColumnLock();
53340 cm.setLocked(index, true, true);
53341 cm.moveColumn(index, lc);
53342 this.grid.fireEvent("columnmove", index, lc);
53344 cm.setLocked(index, true);
53348 var lc = cm.getLockedCount();
53349 if((lc-1) != index){
53350 cm.setLocked(index, false, true);
53351 cm.moveColumn(index, lc-1);
53352 this.grid.fireEvent("columnmove", index, lc-1);
53354 cm.setLocked(index, false);
53358 index = cm.getIndexById(item.id.substr(4));
53360 if(item.checked && cm.getColumnCount(true) <= 1){
53361 this.onDenyColumnHide();
53364 cm.setHidden(index, item.checked);
53370 beforeColMenuShow : function(){
53371 var cm = this.cm, colCount = cm.getColumnCount();
53372 this.colMenu.removeAll();
53373 for(var i = 0; i < colCount; i++){
53374 this.colMenu.add(new Roo.menu.CheckItem({
53375 id: "col-"+cm.getColumnId(i),
53376 text: cm.getColumnHeader(i),
53377 checked: !cm.isHidden(i),
53383 handleHdCtx : function(g, index, e){
53385 var hd = this.getHeaderCell(index);
53386 this.hdCtxIndex = index;
53387 var ms = this.hmenu.items, cm = this.cm;
53388 ms.get("asc").setDisabled(!cm.isSortable(index));
53389 ms.get("desc").setDisabled(!cm.isSortable(index));
53390 if(this.grid.enableColLock !== false){
53391 ms.get("lock").setDisabled(cm.isLocked(index));
53392 ms.get("unlock").setDisabled(!cm.isLocked(index));
53394 this.hmenu.show(hd, "tl-bl");
53397 handleHdOver : function(e){
53398 var hd = this.findHeaderCell(e.getTarget());
53399 if(hd && !this.headersDisabled){
53400 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
53401 this.fly(hd).addClass("x-grid-hd-over");
53406 handleHdOut : function(e){
53407 var hd = this.findHeaderCell(e.getTarget());
53409 this.fly(hd).removeClass("x-grid-hd-over");
53413 handleSplitDblClick : function(e, t){
53414 var i = this.getCellIndex(t);
53415 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
53416 this.autoSizeColumn(i, true);
53421 render : function(){
53424 var colCount = cm.getColumnCount();
53426 if(this.grid.monitorWindowResize === true){
53427 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
53429 var header = this.renderHeaders();
53430 var body = this.templates.body.apply({rows:""});
53431 var html = this.templates.master.apply({
53434 lockedHeader: header[0],
53438 //this.updateColumns();
53440 this.grid.getGridEl().dom.innerHTML = html;
53442 this.initElements();
53444 // a kludge to fix the random scolling effect in webkit
53445 this.el.on("scroll", function() {
53446 this.el.dom.scrollTop=0; // hopefully not recursive..
53449 this.scroller.on("scroll", this.handleScroll, this);
53450 this.lockedBody.on("mousewheel", this.handleWheel, this);
53451 this.mainBody.on("mousewheel", this.handleWheel, this);
53453 this.mainHd.on("mouseover", this.handleHdOver, this);
53454 this.mainHd.on("mouseout", this.handleHdOut, this);
53455 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
53456 {delegate: "."+this.splitClass});
53458 this.lockedHd.on("mouseover", this.handleHdOver, this);
53459 this.lockedHd.on("mouseout", this.handleHdOut, this);
53460 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
53461 {delegate: "."+this.splitClass});
53463 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
53464 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53467 this.updateSplitters();
53469 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
53470 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53471 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53474 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
53475 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
53477 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
53478 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
53480 if(this.grid.enableColLock !== false){
53481 this.hmenu.add('-',
53482 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
53483 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
53486 if(this.grid.enableColumnHide !== false){
53488 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
53489 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
53490 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
53492 this.hmenu.add('-',
53493 {id:"columns", text: this.columnsText, menu: this.colMenu}
53496 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
53498 this.grid.on("headercontextmenu", this.handleHdCtx, this);
53501 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
53502 this.dd = new Roo.grid.GridDragZone(this.grid, {
53503 ddGroup : this.grid.ddGroup || 'GridDD'
53509 for(var i = 0; i < colCount; i++){
53510 if(cm.isHidden(i)){
53511 this.hideColumn(i);
53513 if(cm.config[i].align){
53514 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
53515 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
53519 this.updateHeaderSortState();
53521 this.beforeInitialResize();
53524 // two part rendering gives faster view to the user
53525 this.renderPhase2.defer(1, this);
53528 renderPhase2 : function(){
53529 // render the rows now
53531 if(this.grid.autoSizeColumns){
53532 this.autoSizeColumns();
53536 beforeInitialResize : function(){
53540 onColumnSplitterMoved : function(i, w){
53541 this.userResized = true;
53542 var cm = this.grid.colModel;
53543 cm.setColumnWidth(i, w, true);
53544 var cid = cm.getColumnId(i);
53545 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
53546 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
53547 this.updateSplitters();
53549 this.grid.fireEvent("columnresize", i, w);
53552 syncRowHeights : function(startIndex, endIndex){
53553 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
53554 startIndex = startIndex || 0;
53555 var mrows = this.getBodyTable().rows;
53556 var lrows = this.getLockedTable().rows;
53557 var len = mrows.length-1;
53558 endIndex = Math.min(endIndex || len, len);
53559 for(var i = startIndex; i <= endIndex; i++){
53560 var m = mrows[i], l = lrows[i];
53561 var h = Math.max(m.offsetHeight, l.offsetHeight);
53562 m.style.height = l.style.height = h + "px";
53567 layout : function(initialRender, is2ndPass){
53569 var auto = g.autoHeight;
53570 var scrollOffset = 16;
53571 var c = g.getGridEl(), cm = this.cm,
53572 expandCol = g.autoExpandColumn,
53574 //c.beginMeasure();
53576 if(!c.dom.offsetWidth){ // display:none?
53578 this.lockedWrap.show();
53579 this.mainWrap.show();
53584 var hasLock = this.cm.isLocked(0);
53586 var tbh = this.headerPanel.getHeight();
53587 var bbh = this.footerPanel.getHeight();
53590 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
53591 var newHeight = ch + c.getBorderWidth("tb");
53593 newHeight = Math.min(g.maxHeight, newHeight);
53595 c.setHeight(newHeight);
53599 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
53602 var s = this.scroller;
53604 var csize = c.getSize(true);
53606 this.el.setSize(csize.width, csize.height);
53608 this.headerPanel.setWidth(csize.width);
53609 this.footerPanel.setWidth(csize.width);
53611 var hdHeight = this.mainHd.getHeight();
53612 var vw = csize.width;
53613 var vh = csize.height - (tbh + bbh);
53617 var bt = this.getBodyTable();
53618 var ltWidth = hasLock ?
53619 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
53621 var scrollHeight = bt.offsetHeight;
53622 var scrollWidth = ltWidth + bt.offsetWidth;
53623 var vscroll = false, hscroll = false;
53625 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
53627 var lw = this.lockedWrap, mw = this.mainWrap;
53628 var lb = this.lockedBody, mb = this.mainBody;
53630 setTimeout(function(){
53631 var t = s.dom.offsetTop;
53632 var w = s.dom.clientWidth,
53633 h = s.dom.clientHeight;
53636 lw.setSize(ltWidth, h);
53638 mw.setLeftTop(ltWidth, t);
53639 mw.setSize(w-ltWidth, h);
53641 lb.setHeight(h-hdHeight);
53642 mb.setHeight(h-hdHeight);
53644 if(is2ndPass !== true && !gv.userResized && expandCol){
53645 // high speed resize without full column calculation
53647 var ci = cm.getIndexById(expandCol);
53649 ci = cm.findColumnIndex(expandCol);
53651 ci = Math.max(0, ci); // make sure it's got at least the first col.
53652 var expandId = cm.getColumnId(ci);
53653 var tw = cm.getTotalWidth(false);
53654 var currentWidth = cm.getColumnWidth(ci);
53655 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
53656 if(currentWidth != cw){
53657 cm.setColumnWidth(ci, cw, true);
53658 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
53659 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
53660 gv.updateSplitters();
53661 gv.layout(false, true);
53673 onWindowResize : function(){
53674 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
53680 appendFooter : function(parentEl){
53684 sortAscText : "Sort Ascending",
53685 sortDescText : "Sort Descending",
53686 lockText : "Lock Column",
53687 unlockText : "Unlock Column",
53688 columnsText : "Columns"
53692 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
53693 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
53694 this.proxy.el.addClass('x-grid3-col-dd');
53697 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
53698 handleMouseDown : function(e){
53702 callHandleMouseDown : function(e){
53703 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
53708 * Ext JS Library 1.1.1
53709 * Copyright(c) 2006-2007, Ext JS, LLC.
53711 * Originally Released Under LGPL - original licence link has changed is not relivant.
53714 * <script type="text/javascript">
53718 // This is a support class used internally by the Grid components
53719 Roo.grid.SplitDragZone = function(grid, hd, hd2){
53721 this.view = grid.getView();
53722 this.proxy = this.view.resizeProxy;
53723 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
53724 "gridSplitters" + this.grid.getGridEl().id, {
53725 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
53727 this.setHandleElId(Roo.id(hd));
53728 this.setOuterHandleElId(Roo.id(hd2));
53729 this.scroll = false;
53731 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
53732 fly: Roo.Element.fly,
53734 b4StartDrag : function(x, y){
53735 this.view.headersDisabled = true;
53736 this.proxy.setHeight(this.view.mainWrap.getHeight());
53737 var w = this.cm.getColumnWidth(this.cellIndex);
53738 var minw = Math.max(w-this.grid.minColumnWidth, 0);
53739 this.resetConstraints();
53740 this.setXConstraint(minw, 1000);
53741 this.setYConstraint(0, 0);
53742 this.minX = x - minw;
53743 this.maxX = x + 1000;
53745 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
53749 handleMouseDown : function(e){
53750 ev = Roo.EventObject.setEvent(e);
53751 var t = this.fly(ev.getTarget());
53752 if(t.hasClass("x-grid-split")){
53753 this.cellIndex = this.view.getCellIndex(t.dom);
53754 this.split = t.dom;
53755 this.cm = this.grid.colModel;
53756 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
53757 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
53762 endDrag : function(e){
53763 this.view.headersDisabled = false;
53764 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
53765 var diff = endX - this.startPos;
53766 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
53769 autoOffset : function(){
53770 this.setDelta(0,0);
53774 * Ext JS Library 1.1.1
53775 * Copyright(c) 2006-2007, Ext JS, LLC.
53777 * Originally Released Under LGPL - original licence link has changed is not relivant.
53780 * <script type="text/javascript">
53784 // This is a support class used internally by the Grid components
53785 Roo.grid.GridDragZone = function(grid, config){
53786 this.view = grid.getView();
53787 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
53788 if(this.view.lockedBody){
53789 this.setHandleElId(Roo.id(this.view.mainBody.dom));
53790 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
53792 this.scroll = false;
53794 this.ddel = document.createElement('div');
53795 this.ddel.className = 'x-grid-dd-wrap';
53798 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
53799 ddGroup : "GridDD",
53801 getDragData : function(e){
53802 var t = Roo.lib.Event.getTarget(e);
53803 var rowIndex = this.view.findRowIndex(t);
53804 var sm = this.grid.selModel;
53806 //Roo.log(rowIndex);
53808 if (sm.getSelectedCell) {
53809 // cell selection..
53810 if (!sm.getSelectedCell()) {
53813 if (rowIndex != sm.getSelectedCell()[0]) {
53819 if(rowIndex !== false){
53824 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
53826 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
53829 if (e.hasModifier()){
53830 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
53833 Roo.log("getDragData");
53838 rowIndex: rowIndex,
53839 selections:sm.getSelections ? sm.getSelections() : (
53840 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
53847 onInitDrag : function(e){
53848 var data = this.dragData;
53849 this.ddel.innerHTML = this.grid.getDragDropText();
53850 this.proxy.update(this.ddel);
53851 // fire start drag?
53854 afterRepair : function(){
53855 this.dragging = false;
53858 getRepairXY : function(e, data){
53862 onEndDrag : function(data, e){
53866 onValidDrop : function(dd, e, id){
53871 beforeInvalidDrop : function(e, id){
53876 * Ext JS Library 1.1.1
53877 * Copyright(c) 2006-2007, Ext JS, LLC.
53879 * Originally Released Under LGPL - original licence link has changed is not relivant.
53882 * <script type="text/javascript">
53887 * @class Roo.grid.ColumnModel
53888 * @extends Roo.util.Observable
53889 * This is the default implementation of a ColumnModel used by the Grid. It defines
53890 * the columns in the grid.
53893 var colModel = new Roo.grid.ColumnModel([
53894 {header: "Ticker", width: 60, sortable: true, locked: true},
53895 {header: "Company Name", width: 150, sortable: true},
53896 {header: "Market Cap.", width: 100, sortable: true},
53897 {header: "$ Sales", width: 100, sortable: true, renderer: money},
53898 {header: "Employees", width: 100, sortable: true, resizable: false}
53903 * The config options listed for this class are options which may appear in each
53904 * individual column definition.
53905 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
53907 * @param {Object} config An Array of column config objects. See this class's
53908 * config objects for details.
53910 Roo.grid.ColumnModel = function(config){
53912 * The config passed into the constructor
53914 this.config = config;
53917 // if no id, create one
53918 // if the column does not have a dataIndex mapping,
53919 // map it to the order it is in the config
53920 for(var i = 0, len = config.length; i < len; i++){
53922 if(typeof c.dataIndex == "undefined"){
53925 if(typeof c.renderer == "string"){
53926 c.renderer = Roo.util.Format[c.renderer];
53928 if(typeof c.id == "undefined"){
53931 if(c.editor && c.editor.xtype){
53932 c.editor = Roo.factory(c.editor, Roo.grid);
53934 if(c.editor && c.editor.isFormField){
53935 c.editor = new Roo.grid.GridEditor(c.editor);
53937 this.lookup[c.id] = c;
53941 * The width of columns which have no width specified (defaults to 100)
53944 this.defaultWidth = 100;
53947 * Default sortable of columns which have no sortable specified (defaults to false)
53950 this.defaultSortable = false;
53954 * @event widthchange
53955 * Fires when the width of a column changes.
53956 * @param {ColumnModel} this
53957 * @param {Number} columnIndex The column index
53958 * @param {Number} newWidth The new width
53960 "widthchange": true,
53962 * @event headerchange
53963 * Fires when the text of a header changes.
53964 * @param {ColumnModel} this
53965 * @param {Number} columnIndex The column index
53966 * @param {Number} newText The new header text
53968 "headerchange": true,
53970 * @event hiddenchange
53971 * Fires when a column is hidden or "unhidden".
53972 * @param {ColumnModel} this
53973 * @param {Number} columnIndex The column index
53974 * @param {Boolean} hidden true if hidden, false otherwise
53976 "hiddenchange": true,
53978 * @event columnmoved
53979 * Fires when a column is moved.
53980 * @param {ColumnModel} this
53981 * @param {Number} oldIndex
53982 * @param {Number} newIndex
53984 "columnmoved" : true,
53986 * @event columlockchange
53987 * Fires when a column's locked state is changed
53988 * @param {ColumnModel} this
53989 * @param {Number} colIndex
53990 * @param {Boolean} locked true if locked
53992 "columnlockchange" : true
53994 Roo.grid.ColumnModel.superclass.constructor.call(this);
53996 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
53998 * @cfg {String} header The header text to display in the Grid view.
54001 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
54002 * {@link Roo.data.Record} definition from which to draw the column's value. If not
54003 * specified, the column's index is used as an index into the Record's data Array.
54006 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
54007 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
54010 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
54011 * Defaults to the value of the {@link #defaultSortable} property.
54012 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
54015 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
54018 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
54021 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
54024 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
54027 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
54028 * given the cell's data value. See {@link #setRenderer}. If not specified, the
54029 * default renderer uses the raw data value.
54032 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
54035 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
54039 * Returns the id of the column at the specified index.
54040 * @param {Number} index The column index
54041 * @return {String} the id
54043 getColumnId : function(index){
54044 return this.config[index].id;
54048 * Returns the column for a specified id.
54049 * @param {String} id The column id
54050 * @return {Object} the column
54052 getColumnById : function(id){
54053 return this.lookup[id];
54058 * Returns the column for a specified dataIndex.
54059 * @param {String} dataIndex The column dataIndex
54060 * @return {Object|Boolean} the column or false if not found
54062 getColumnByDataIndex: function(dataIndex){
54063 var index = this.findColumnIndex(dataIndex);
54064 return index > -1 ? this.config[index] : false;
54068 * Returns the index for a specified column id.
54069 * @param {String} id The column id
54070 * @return {Number} the index, or -1 if not found
54072 getIndexById : function(id){
54073 for(var i = 0, len = this.config.length; i < len; i++){
54074 if(this.config[i].id == id){
54082 * Returns the index for a specified column dataIndex.
54083 * @param {String} dataIndex The column dataIndex
54084 * @return {Number} the index, or -1 if not found
54087 findColumnIndex : function(dataIndex){
54088 for(var i = 0, len = this.config.length; i < len; i++){
54089 if(this.config[i].dataIndex == dataIndex){
54097 moveColumn : function(oldIndex, newIndex){
54098 var c = this.config[oldIndex];
54099 this.config.splice(oldIndex, 1);
54100 this.config.splice(newIndex, 0, c);
54101 this.dataMap = null;
54102 this.fireEvent("columnmoved", this, oldIndex, newIndex);
54105 isLocked : function(colIndex){
54106 return this.config[colIndex].locked === true;
54109 setLocked : function(colIndex, value, suppressEvent){
54110 if(this.isLocked(colIndex) == value){
54113 this.config[colIndex].locked = value;
54114 if(!suppressEvent){
54115 this.fireEvent("columnlockchange", this, colIndex, value);
54119 getTotalLockedWidth : function(){
54120 var totalWidth = 0;
54121 for(var i = 0; i < this.config.length; i++){
54122 if(this.isLocked(i) && !this.isHidden(i)){
54123 this.totalWidth += this.getColumnWidth(i);
54129 getLockedCount : function(){
54130 for(var i = 0, len = this.config.length; i < len; i++){
54131 if(!this.isLocked(i)){
54138 * Returns the number of columns.
54141 getColumnCount : function(visibleOnly){
54142 if(visibleOnly === true){
54144 for(var i = 0, len = this.config.length; i < len; i++){
54145 if(!this.isHidden(i)){
54151 return this.config.length;
54155 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
54156 * @param {Function} fn
54157 * @param {Object} scope (optional)
54158 * @return {Array} result
54160 getColumnsBy : function(fn, scope){
54162 for(var i = 0, len = this.config.length; i < len; i++){
54163 var c = this.config[i];
54164 if(fn.call(scope||this, c, i) === true){
54172 * Returns true if the specified column is sortable.
54173 * @param {Number} col The column index
54174 * @return {Boolean}
54176 isSortable : function(col){
54177 if(typeof this.config[col].sortable == "undefined"){
54178 return this.defaultSortable;
54180 return this.config[col].sortable;
54184 * Returns the rendering (formatting) function defined for the column.
54185 * @param {Number} col The column index.
54186 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
54188 getRenderer : function(col){
54189 if(!this.config[col].renderer){
54190 return Roo.grid.ColumnModel.defaultRenderer;
54192 return this.config[col].renderer;
54196 * Sets the rendering (formatting) function for a column.
54197 * @param {Number} col The column index
54198 * @param {Function} fn The function to use to process the cell's raw data
54199 * to return HTML markup for the grid view. The render function is called with
54200 * the following parameters:<ul>
54201 * <li>Data value.</li>
54202 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
54203 * <li>css A CSS style string to apply to the table cell.</li>
54204 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
54205 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
54206 * <li>Row index</li>
54207 * <li>Column index</li>
54208 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
54210 setRenderer : function(col, fn){
54211 this.config[col].renderer = fn;
54215 * Returns the width for the specified column.
54216 * @param {Number} col The column index
54219 getColumnWidth : function(col){
54220 return this.config[col].width * 1 || this.defaultWidth;
54224 * Sets the width for a column.
54225 * @param {Number} col The column index
54226 * @param {Number} width The new width
54228 setColumnWidth : function(col, width, suppressEvent){
54229 this.config[col].width = width;
54230 this.totalWidth = null;
54231 if(!suppressEvent){
54232 this.fireEvent("widthchange", this, col, width);
54237 * Returns the total width of all columns.
54238 * @param {Boolean} includeHidden True to include hidden column widths
54241 getTotalWidth : function(includeHidden){
54242 if(!this.totalWidth){
54243 this.totalWidth = 0;
54244 for(var i = 0, len = this.config.length; i < len; i++){
54245 if(includeHidden || !this.isHidden(i)){
54246 this.totalWidth += this.getColumnWidth(i);
54250 return this.totalWidth;
54254 * Returns the header for the specified column.
54255 * @param {Number} col The column index
54258 getColumnHeader : function(col){
54259 return this.config[col].header;
54263 * Sets the header for a column.
54264 * @param {Number} col The column index
54265 * @param {String} header The new header
54267 setColumnHeader : function(col, header){
54268 this.config[col].header = header;
54269 this.fireEvent("headerchange", this, col, header);
54273 * Returns the tooltip for the specified column.
54274 * @param {Number} col The column index
54277 getColumnTooltip : function(col){
54278 return this.config[col].tooltip;
54281 * Sets the tooltip for a column.
54282 * @param {Number} col The column index
54283 * @param {String} tooltip The new tooltip
54285 setColumnTooltip : function(col, tooltip){
54286 this.config[col].tooltip = tooltip;
54290 * Returns the dataIndex for the specified column.
54291 * @param {Number} col The column index
54294 getDataIndex : function(col){
54295 return this.config[col].dataIndex;
54299 * Sets the dataIndex for a column.
54300 * @param {Number} col The column index
54301 * @param {Number} dataIndex The new dataIndex
54303 setDataIndex : function(col, dataIndex){
54304 this.config[col].dataIndex = dataIndex;
54310 * Returns true if the cell is editable.
54311 * @param {Number} colIndex The column index
54312 * @param {Number} rowIndex The row index
54313 * @return {Boolean}
54315 isCellEditable : function(colIndex, rowIndex){
54316 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
54320 * Returns the editor defined for the cell/column.
54321 * return false or null to disable editing.
54322 * @param {Number} colIndex The column index
54323 * @param {Number} rowIndex The row index
54326 getCellEditor : function(colIndex, rowIndex){
54327 return this.config[colIndex].editor;
54331 * Sets if a column is editable.
54332 * @param {Number} col The column index
54333 * @param {Boolean} editable True if the column is editable
54335 setEditable : function(col, editable){
54336 this.config[col].editable = editable;
54341 * Returns true if the column is hidden.
54342 * @param {Number} colIndex The column index
54343 * @return {Boolean}
54345 isHidden : function(colIndex){
54346 return this.config[colIndex].hidden;
54351 * Returns true if the column width cannot be changed
54353 isFixed : function(colIndex){
54354 return this.config[colIndex].fixed;
54358 * Returns true if the column can be resized
54359 * @return {Boolean}
54361 isResizable : function(colIndex){
54362 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
54365 * Sets if a column is hidden.
54366 * @param {Number} colIndex The column index
54367 * @param {Boolean} hidden True if the column is hidden
54369 setHidden : function(colIndex, hidden){
54370 this.config[colIndex].hidden = hidden;
54371 this.totalWidth = null;
54372 this.fireEvent("hiddenchange", this, colIndex, hidden);
54376 * Sets the editor for a column.
54377 * @param {Number} col The column index
54378 * @param {Object} editor The editor object
54380 setEditor : function(col, editor){
54381 this.config[col].editor = editor;
54385 Roo.grid.ColumnModel.defaultRenderer = function(value){
54386 if(typeof value == "string" && value.length < 1){
54392 // Alias for backwards compatibility
54393 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
54396 * Ext JS Library 1.1.1
54397 * Copyright(c) 2006-2007, Ext JS, LLC.
54399 * Originally Released Under LGPL - original licence link has changed is not relivant.
54402 * <script type="text/javascript">
54406 * @class Roo.grid.AbstractSelectionModel
54407 * @extends Roo.util.Observable
54408 * Abstract base class for grid SelectionModels. It provides the interface that should be
54409 * implemented by descendant classes. This class should not be directly instantiated.
54412 Roo.grid.AbstractSelectionModel = function(){
54413 this.locked = false;
54414 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
54417 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
54418 /** @ignore Called by the grid automatically. Do not call directly. */
54419 init : function(grid){
54425 * Locks the selections.
54428 this.locked = true;
54432 * Unlocks the selections.
54434 unlock : function(){
54435 this.locked = false;
54439 * Returns true if the selections are locked.
54440 * @return {Boolean}
54442 isLocked : function(){
54443 return this.locked;
54447 * Ext JS Library 1.1.1
54448 * Copyright(c) 2006-2007, Ext JS, LLC.
54450 * Originally Released Under LGPL - original licence link has changed is not relivant.
54453 * <script type="text/javascript">
54456 * @extends Roo.grid.AbstractSelectionModel
54457 * @class Roo.grid.RowSelectionModel
54458 * The default SelectionModel used by {@link Roo.grid.Grid}.
54459 * It supports multiple selections and keyboard selection/navigation.
54461 * @param {Object} config
54463 Roo.grid.RowSelectionModel = function(config){
54464 Roo.apply(this, config);
54465 this.selections = new Roo.util.MixedCollection(false, function(o){
54470 this.lastActive = false;
54474 * @event selectionchange
54475 * Fires when the selection changes
54476 * @param {SelectionModel} this
54478 "selectionchange" : true,
54480 * @event afterselectionchange
54481 * Fires after the selection changes (eg. by key press or clicking)
54482 * @param {SelectionModel} this
54484 "afterselectionchange" : true,
54486 * @event beforerowselect
54487 * Fires when a row is selected being selected, return false to cancel.
54488 * @param {SelectionModel} this
54489 * @param {Number} rowIndex The selected index
54490 * @param {Boolean} keepExisting False if other selections will be cleared
54492 "beforerowselect" : true,
54495 * Fires when a row is selected.
54496 * @param {SelectionModel} this
54497 * @param {Number} rowIndex The selected index
54498 * @param {Roo.data.Record} r The record
54500 "rowselect" : true,
54502 * @event rowdeselect
54503 * Fires when a row is deselected.
54504 * @param {SelectionModel} this
54505 * @param {Number} rowIndex The selected index
54507 "rowdeselect" : true
54509 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
54510 this.locked = false;
54513 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
54515 * @cfg {Boolean} singleSelect
54516 * True to allow selection of only one row at a time (defaults to false)
54518 singleSelect : false,
54521 initEvents : function(){
54523 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
54524 this.grid.on("mousedown", this.handleMouseDown, this);
54525 }else{ // allow click to work like normal
54526 this.grid.on("rowclick", this.handleDragableRowClick, this);
54529 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
54530 "up" : function(e){
54532 this.selectPrevious(e.shiftKey);
54533 }else if(this.last !== false && this.lastActive !== false){
54534 var last = this.last;
54535 this.selectRange(this.last, this.lastActive-1);
54536 this.grid.getView().focusRow(this.lastActive);
54537 if(last !== false){
54541 this.selectFirstRow();
54543 this.fireEvent("afterselectionchange", this);
54545 "down" : function(e){
54547 this.selectNext(e.shiftKey);
54548 }else if(this.last !== false && this.lastActive !== false){
54549 var last = this.last;
54550 this.selectRange(this.last, this.lastActive+1);
54551 this.grid.getView().focusRow(this.lastActive);
54552 if(last !== false){
54556 this.selectFirstRow();
54558 this.fireEvent("afterselectionchange", this);
54563 var view = this.grid.view;
54564 view.on("refresh", this.onRefresh, this);
54565 view.on("rowupdated", this.onRowUpdated, this);
54566 view.on("rowremoved", this.onRemove, this);
54570 onRefresh : function(){
54571 var ds = this.grid.dataSource, i, v = this.grid.view;
54572 var s = this.selections;
54573 s.each(function(r){
54574 if((i = ds.indexOfId(r.id)) != -1){
54583 onRemove : function(v, index, r){
54584 this.selections.remove(r);
54588 onRowUpdated : function(v, index, r){
54589 if(this.isSelected(r)){
54590 v.onRowSelect(index);
54596 * @param {Array} records The records to select
54597 * @param {Boolean} keepExisting (optional) True to keep existing selections
54599 selectRecords : function(records, keepExisting){
54601 this.clearSelections();
54603 var ds = this.grid.dataSource;
54604 for(var i = 0, len = records.length; i < len; i++){
54605 this.selectRow(ds.indexOf(records[i]), true);
54610 * Gets the number of selected rows.
54613 getCount : function(){
54614 return this.selections.length;
54618 * Selects the first row in the grid.
54620 selectFirstRow : function(){
54625 * Select the last row.
54626 * @param {Boolean} keepExisting (optional) True to keep existing selections
54628 selectLastRow : function(keepExisting){
54629 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
54633 * Selects the row immediately following the last selected row.
54634 * @param {Boolean} keepExisting (optional) True to keep existing selections
54636 selectNext : function(keepExisting){
54637 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
54638 this.selectRow(this.last+1, keepExisting);
54639 this.grid.getView().focusRow(this.last);
54644 * Selects the row that precedes the last selected row.
54645 * @param {Boolean} keepExisting (optional) True to keep existing selections
54647 selectPrevious : function(keepExisting){
54649 this.selectRow(this.last-1, keepExisting);
54650 this.grid.getView().focusRow(this.last);
54655 * Returns the selected records
54656 * @return {Array} Array of selected records
54658 getSelections : function(){
54659 return [].concat(this.selections.items);
54663 * Returns the first selected record.
54666 getSelected : function(){
54667 return this.selections.itemAt(0);
54672 * Clears all selections.
54674 clearSelections : function(fast){
54675 if(this.locked) return;
54677 var ds = this.grid.dataSource;
54678 var s = this.selections;
54679 s.each(function(r){
54680 this.deselectRow(ds.indexOfId(r.id));
54684 this.selections.clear();
54691 * Selects all rows.
54693 selectAll : function(){
54694 if(this.locked) return;
54695 this.selections.clear();
54696 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
54697 this.selectRow(i, true);
54702 * Returns True if there is a selection.
54703 * @return {Boolean}
54705 hasSelection : function(){
54706 return this.selections.length > 0;
54710 * Returns True if the specified row is selected.
54711 * @param {Number/Record} record The record or index of the record to check
54712 * @return {Boolean}
54714 isSelected : function(index){
54715 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
54716 return (r && this.selections.key(r.id) ? true : false);
54720 * Returns True if the specified record id is selected.
54721 * @param {String} id The id of record to check
54722 * @return {Boolean}
54724 isIdSelected : function(id){
54725 return (this.selections.key(id) ? true : false);
54729 handleMouseDown : function(e, t){
54730 var view = this.grid.getView(), rowIndex;
54731 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
54734 if(e.shiftKey && this.last !== false){
54735 var last = this.last;
54736 this.selectRange(last, rowIndex, e.ctrlKey);
54737 this.last = last; // reset the last
54738 view.focusRow(rowIndex);
54740 var isSelected = this.isSelected(rowIndex);
54741 if(e.button !== 0 && isSelected){
54742 view.focusRow(rowIndex);
54743 }else if(e.ctrlKey && isSelected){
54744 this.deselectRow(rowIndex);
54745 }else if(!isSelected){
54746 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
54747 view.focusRow(rowIndex);
54750 this.fireEvent("afterselectionchange", this);
54753 handleDragableRowClick : function(grid, rowIndex, e)
54755 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
54756 this.selectRow(rowIndex, false);
54757 grid.view.focusRow(rowIndex);
54758 this.fireEvent("afterselectionchange", this);
54763 * Selects multiple rows.
54764 * @param {Array} rows Array of the indexes of the row to select
54765 * @param {Boolean} keepExisting (optional) True to keep existing selections
54767 selectRows : function(rows, keepExisting){
54769 this.clearSelections();
54771 for(var i = 0, len = rows.length; i < len; i++){
54772 this.selectRow(rows[i], true);
54777 * Selects a range of rows. All rows in between startRow and endRow are also selected.
54778 * @param {Number} startRow The index of the first row in the range
54779 * @param {Number} endRow The index of the last row in the range
54780 * @param {Boolean} keepExisting (optional) True to retain existing selections
54782 selectRange : function(startRow, endRow, keepExisting){
54783 if(this.locked) return;
54785 this.clearSelections();
54787 if(startRow <= endRow){
54788 for(var i = startRow; i <= endRow; i++){
54789 this.selectRow(i, true);
54792 for(var i = startRow; i >= endRow; i--){
54793 this.selectRow(i, true);
54799 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
54800 * @param {Number} startRow The index of the first row in the range
54801 * @param {Number} endRow The index of the last row in the range
54803 deselectRange : function(startRow, endRow, preventViewNotify){
54804 if(this.locked) return;
54805 for(var i = startRow; i <= endRow; i++){
54806 this.deselectRow(i, preventViewNotify);
54812 * @param {Number} row The index of the row to select
54813 * @param {Boolean} keepExisting (optional) True to keep existing selections
54815 selectRow : function(index, keepExisting, preventViewNotify){
54816 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
54817 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
54818 if(!keepExisting || this.singleSelect){
54819 this.clearSelections();
54821 var r = this.grid.dataSource.getAt(index);
54822 this.selections.add(r);
54823 this.last = this.lastActive = index;
54824 if(!preventViewNotify){
54825 this.grid.getView().onRowSelect(index);
54827 this.fireEvent("rowselect", this, index, r);
54828 this.fireEvent("selectionchange", this);
54834 * @param {Number} row The index of the row to deselect
54836 deselectRow : function(index, preventViewNotify){
54837 if(this.locked) return;
54838 if(this.last == index){
54841 if(this.lastActive == index){
54842 this.lastActive = false;
54844 var r = this.grid.dataSource.getAt(index);
54845 this.selections.remove(r);
54846 if(!preventViewNotify){
54847 this.grid.getView().onRowDeselect(index);
54849 this.fireEvent("rowdeselect", this, index);
54850 this.fireEvent("selectionchange", this);
54854 restoreLast : function(){
54856 this.last = this._last;
54861 acceptsNav : function(row, col, cm){
54862 return !cm.isHidden(col) && cm.isCellEditable(col, row);
54866 onEditorKey : function(field, e){
54867 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
54872 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
54874 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
54876 }else if(k == e.ENTER && !e.ctrlKey){
54880 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
54882 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
54884 }else if(k == e.ESC){
54888 g.startEditing(newCell[0], newCell[1]);
54893 * Ext JS Library 1.1.1
54894 * Copyright(c) 2006-2007, Ext JS, LLC.
54896 * Originally Released Under LGPL - original licence link has changed is not relivant.
54899 * <script type="text/javascript">
54902 * @class Roo.grid.CellSelectionModel
54903 * @extends Roo.grid.AbstractSelectionModel
54904 * This class provides the basic implementation for cell selection in a grid.
54906 * @param {Object} config The object containing the configuration of this model.
54907 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
54909 Roo.grid.CellSelectionModel = function(config){
54910 Roo.apply(this, config);
54912 this.selection = null;
54916 * @event beforerowselect
54917 * Fires before a cell is selected.
54918 * @param {SelectionModel} this
54919 * @param {Number} rowIndex The selected row index
54920 * @param {Number} colIndex The selected cell index
54922 "beforecellselect" : true,
54924 * @event cellselect
54925 * Fires when a cell is selected.
54926 * @param {SelectionModel} this
54927 * @param {Number} rowIndex The selected row index
54928 * @param {Number} colIndex The selected cell index
54930 "cellselect" : true,
54932 * @event selectionchange
54933 * Fires when the active selection changes.
54934 * @param {SelectionModel} this
54935 * @param {Object} selection null for no selection or an object (o) with two properties
54937 <li>o.record: the record object for the row the selection is in</li>
54938 <li>o.cell: An array of [rowIndex, columnIndex]</li>
54941 "selectionchange" : true,
54944 * Fires when the tab (or enter) was pressed on the last editable cell
54945 * You can use this to trigger add new row.
54946 * @param {SelectionModel} this
54950 * @event beforeeditnext
54951 * Fires before the next editable sell is made active
54952 * You can use this to skip to another cell or fire the tabend
54953 * if you set cell to false
54954 * @param {Object} eventdata object : { cell : [ row, col ] }
54956 "beforeeditnext" : true
54958 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
54961 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
54963 enter_is_tab: false,
54966 initEvents : function(){
54967 this.grid.on("mousedown", this.handleMouseDown, this);
54968 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
54969 var view = this.grid.view;
54970 view.on("refresh", this.onViewChange, this);
54971 view.on("rowupdated", this.onRowUpdated, this);
54972 view.on("beforerowremoved", this.clearSelections, this);
54973 view.on("beforerowsinserted", this.clearSelections, this);
54974 if(this.grid.isEditor){
54975 this.grid.on("beforeedit", this.beforeEdit, this);
54980 beforeEdit : function(e){
54981 this.select(e.row, e.column, false, true, e.record);
54985 onRowUpdated : function(v, index, r){
54986 if(this.selection && this.selection.record == r){
54987 v.onCellSelect(index, this.selection.cell[1]);
54992 onViewChange : function(){
54993 this.clearSelections(true);
54997 * Returns the currently selected cell,.
54998 * @return {Array} The selected cell (row, column) or null if none selected.
55000 getSelectedCell : function(){
55001 return this.selection ? this.selection.cell : null;
55005 * Clears all selections.
55006 * @param {Boolean} true to prevent the gridview from being notified about the change.
55008 clearSelections : function(preventNotify){
55009 var s = this.selection;
55011 if(preventNotify !== true){
55012 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
55014 this.selection = null;
55015 this.fireEvent("selectionchange", this, null);
55020 * Returns true if there is a selection.
55021 * @return {Boolean}
55023 hasSelection : function(){
55024 return this.selection ? true : false;
55028 handleMouseDown : function(e, t){
55029 var v = this.grid.getView();
55030 if(this.isLocked()){
55033 var row = v.findRowIndex(t);
55034 var cell = v.findCellIndex(t);
55035 if(row !== false && cell !== false){
55036 this.select(row, cell);
55042 * @param {Number} rowIndex
55043 * @param {Number} collIndex
55045 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
55046 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
55047 this.clearSelections();
55048 r = r || this.grid.dataSource.getAt(rowIndex);
55051 cell : [rowIndex, colIndex]
55053 if(!preventViewNotify){
55054 var v = this.grid.getView();
55055 v.onCellSelect(rowIndex, colIndex);
55056 if(preventFocus !== true){
55057 v.focusCell(rowIndex, colIndex);
55060 this.fireEvent("cellselect", this, rowIndex, colIndex);
55061 this.fireEvent("selectionchange", this, this.selection);
55066 isSelectable : function(rowIndex, colIndex, cm){
55067 return !cm.isHidden(colIndex);
55071 handleKeyDown : function(e){
55072 //Roo.log('Cell Sel Model handleKeyDown');
55073 if(!e.isNavKeyPress()){
55076 var g = this.grid, s = this.selection;
55079 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
55081 this.select(cell[0], cell[1]);
55086 var walk = function(row, col, step){
55087 return g.walkCells(row, col, step, sm.isSelectable, sm);
55089 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
55096 // handled by onEditorKey
55097 if (g.isEditor && g.editing) {
55101 newCell = walk(r, c-1, -1);
55103 newCell = walk(r, c+1, 1);
55108 newCell = walk(r+1, c, 1);
55112 newCell = walk(r-1, c, -1);
55116 newCell = walk(r, c+1, 1);
55120 newCell = walk(r, c-1, -1);
55125 if(g.isEditor && !g.editing){
55126 g.startEditing(r, c);
55135 this.select(newCell[0], newCell[1]);
55141 acceptsNav : function(row, col, cm){
55142 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55146 * @param {Number} field (not used) - as it's normally used as a listener
55147 * @param {Number} e - event - fake it by using
55149 * var e = Roo.EventObjectImpl.prototype;
55150 * e.keyCode = e.TAB
55154 onEditorKey : function(field, e){
55156 var k = e.getKey(),
55159 ed = g.activeEditor,
55161 ///Roo.log('onEditorKey' + k);
55164 if (this.enter_is_tab && k == e.ENTER) {
55170 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55172 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55178 } else if(k == e.ENTER && !e.ctrlKey){
55181 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55183 } else if(k == e.ESC){
55188 var ecall = { cell : newCell, forward : forward };
55189 this.fireEvent('beforeeditnext', ecall );
55190 newCell = ecall.cell;
55191 forward = ecall.forward;
55195 //Roo.log('next cell after edit');
55196 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
55197 } else if (forward) {
55198 // tabbed past last
55199 this.fireEvent.defer(100, this, ['tabend',this]);
55204 * Ext JS Library 1.1.1
55205 * Copyright(c) 2006-2007, Ext JS, LLC.
55207 * Originally Released Under LGPL - original licence link has changed is not relivant.
55210 * <script type="text/javascript">
55214 * @class Roo.grid.EditorGrid
55215 * @extends Roo.grid.Grid
55216 * Class for creating and editable grid.
55217 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55218 * The container MUST have some type of size defined for the grid to fill. The container will be
55219 * automatically set to position relative if it isn't already.
55220 * @param {Object} dataSource The data model to bind to
55221 * @param {Object} colModel The column model with info about this grid's columns
55223 Roo.grid.EditorGrid = function(container, config){
55224 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
55225 this.getGridEl().addClass("xedit-grid");
55227 if(!this.selModel){
55228 this.selModel = new Roo.grid.CellSelectionModel();
55231 this.activeEditor = null;
55235 * @event beforeedit
55236 * Fires before cell editing is triggered. The edit event object has the following properties <br />
55237 * <ul style="padding:5px;padding-left:16px;">
55238 * <li>grid - This grid</li>
55239 * <li>record - The record being edited</li>
55240 * <li>field - The field name being edited</li>
55241 * <li>value - The value for the field being edited.</li>
55242 * <li>row - The grid row index</li>
55243 * <li>column - The grid column index</li>
55244 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55246 * @param {Object} e An edit event (see above for description)
55248 "beforeedit" : true,
55251 * Fires after a cell is edited. <br />
55252 * <ul style="padding:5px;padding-left:16px;">
55253 * <li>grid - This grid</li>
55254 * <li>record - The record being edited</li>
55255 * <li>field - The field name being edited</li>
55256 * <li>value - The value being set</li>
55257 * <li>originalValue - The original value for the field, before the edit.</li>
55258 * <li>row - The grid row index</li>
55259 * <li>column - The grid column index</li>
55261 * @param {Object} e An edit event (see above for description)
55263 "afteredit" : true,
55265 * @event validateedit
55266 * Fires after a cell is edited, but before the value is set in the record.
55267 * You can use this to modify the value being set in the field, Return false
55268 * to cancel the change. The edit event object has the following properties <br />
55269 * <ul style="padding:5px;padding-left:16px;">
55270 * <li>editor - This editor</li>
55271 * <li>grid - This grid</li>
55272 * <li>record - The record being edited</li>
55273 * <li>field - The field name being edited</li>
55274 * <li>value - The value being set</li>
55275 * <li>originalValue - The original value for the field, before the edit.</li>
55276 * <li>row - The grid row index</li>
55277 * <li>column - The grid column index</li>
55278 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55280 * @param {Object} e An edit event (see above for description)
55282 "validateedit" : true
55284 this.on("bodyscroll", this.stopEditing, this);
55285 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
55288 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
55290 * @cfg {Number} clicksToEdit
55291 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
55298 trackMouseOver: false, // causes very odd FF errors
55300 onCellDblClick : function(g, row, col){
55301 this.startEditing(row, col);
55304 onEditComplete : function(ed, value, startValue){
55305 this.editing = false;
55306 this.activeEditor = null;
55307 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
55309 var field = this.colModel.getDataIndex(ed.col);
55314 originalValue: startValue,
55321 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
55324 if(String(value) !== String(startValue)){
55326 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
55327 r.set(field, e.value);
55328 // if we are dealing with a combo box..
55329 // then we also set the 'name' colum to be the displayField
55330 if (ed.field.displayField && ed.field.name) {
55331 r.set(ed.field.name, ed.field.el.dom.value);
55334 delete e.cancel; //?? why!!!
55335 this.fireEvent("afteredit", e);
55338 this.fireEvent("afteredit", e); // always fire it!
55340 this.view.focusCell(ed.row, ed.col);
55344 * Starts editing the specified for the specified row/column
55345 * @param {Number} rowIndex
55346 * @param {Number} colIndex
55348 startEditing : function(row, col){
55349 this.stopEditing();
55350 if(this.colModel.isCellEditable(col, row)){
55351 this.view.ensureVisible(row, col, true);
55353 var r = this.dataSource.getAt(row);
55354 var field = this.colModel.getDataIndex(col);
55355 var cell = Roo.get(this.view.getCell(row,col));
55360 value: r.data[field],
55365 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
55366 this.editing = true;
55367 var ed = this.colModel.getCellEditor(col, row);
55373 ed.render(ed.parentEl || document.body);
55379 (function(){ // complex but required for focus issues in safari, ie and opera
55383 ed.on("complete", this.onEditComplete, this, {single: true});
55384 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
55385 this.activeEditor = ed;
55386 var v = r.data[field];
55387 ed.startEdit(this.view.getCell(row, col), v);
55388 // combo's with 'displayField and name set
55389 if (ed.field.displayField && ed.field.name) {
55390 ed.field.el.dom.value = r.data[ed.field.name];
55394 }).defer(50, this);
55400 * Stops any active editing
55402 stopEditing : function(){
55403 if(this.activeEditor){
55404 this.activeEditor.completeEdit();
55406 this.activeEditor = null;
55410 * Called to get grid's drag proxy text, by default returns this.ddText.
55413 getDragDropText : function(){
55414 var count = this.selModel.getSelectedCell() ? 1 : 0;
55415 return String.format(this.ddText, count, count == 1 ? '' : 's');
55420 * Ext JS Library 1.1.1
55421 * Copyright(c) 2006-2007, Ext JS, LLC.
55423 * Originally Released Under LGPL - original licence link has changed is not relivant.
55426 * <script type="text/javascript">
55429 // private - not really -- you end up using it !
55430 // This is a support class used internally by the Grid components
55433 * @class Roo.grid.GridEditor
55434 * @extends Roo.Editor
55435 * Class for creating and editable grid elements.
55436 * @param {Object} config any settings (must include field)
55438 Roo.grid.GridEditor = function(field, config){
55439 if (!config && field.field) {
55441 field = Roo.factory(config.field, Roo.form);
55443 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
55444 field.monitorTab = false;
55447 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
55450 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
55453 alignment: "tl-tl",
55456 cls: "x-small-editor x-grid-editor",
55461 * Ext JS Library 1.1.1
55462 * Copyright(c) 2006-2007, Ext JS, LLC.
55464 * Originally Released Under LGPL - original licence link has changed is not relivant.
55467 * <script type="text/javascript">
55472 Roo.grid.PropertyRecord = Roo.data.Record.create([
55473 {name:'name',type:'string'}, 'value'
55477 Roo.grid.PropertyStore = function(grid, source){
55479 this.store = new Roo.data.Store({
55480 recordType : Roo.grid.PropertyRecord
55482 this.store.on('update', this.onUpdate, this);
55484 this.setSource(source);
55486 Roo.grid.PropertyStore.superclass.constructor.call(this);
55491 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
55492 setSource : function(o){
55494 this.store.removeAll();
55497 if(this.isEditableValue(o[k])){
55498 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
55501 this.store.loadRecords({records: data}, {}, true);
55504 onUpdate : function(ds, record, type){
55505 if(type == Roo.data.Record.EDIT){
55506 var v = record.data['value'];
55507 var oldValue = record.modified['value'];
55508 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
55509 this.source[record.id] = v;
55511 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
55518 getProperty : function(row){
55519 return this.store.getAt(row);
55522 isEditableValue: function(val){
55523 if(val && val instanceof Date){
55525 }else if(typeof val == 'object' || typeof val == 'function'){
55531 setValue : function(prop, value){
55532 this.source[prop] = value;
55533 this.store.getById(prop).set('value', value);
55536 getSource : function(){
55537 return this.source;
55541 Roo.grid.PropertyColumnModel = function(grid, store){
55544 g.PropertyColumnModel.superclass.constructor.call(this, [
55545 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
55546 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
55548 this.store = store;
55549 this.bselect = Roo.DomHelper.append(document.body, {
55550 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
55551 {tag: 'option', value: 'true', html: 'true'},
55552 {tag: 'option', value: 'false', html: 'false'}
55555 Roo.id(this.bselect);
55558 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
55559 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
55560 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
55561 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
55562 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
55564 this.renderCellDelegate = this.renderCell.createDelegate(this);
55565 this.renderPropDelegate = this.renderProp.createDelegate(this);
55568 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
55572 valueText : 'Value',
55574 dateFormat : 'm/j/Y',
55577 renderDate : function(dateVal){
55578 return dateVal.dateFormat(this.dateFormat);
55581 renderBool : function(bVal){
55582 return bVal ? 'true' : 'false';
55585 isCellEditable : function(colIndex, rowIndex){
55586 return colIndex == 1;
55589 getRenderer : function(col){
55591 this.renderCellDelegate : this.renderPropDelegate;
55594 renderProp : function(v){
55595 return this.getPropertyName(v);
55598 renderCell : function(val){
55600 if(val instanceof Date){
55601 rv = this.renderDate(val);
55602 }else if(typeof val == 'boolean'){
55603 rv = this.renderBool(val);
55605 return Roo.util.Format.htmlEncode(rv);
55608 getPropertyName : function(name){
55609 var pn = this.grid.propertyNames;
55610 return pn && pn[name] ? pn[name] : name;
55613 getCellEditor : function(colIndex, rowIndex){
55614 var p = this.store.getProperty(rowIndex);
55615 var n = p.data['name'], val = p.data['value'];
55617 if(typeof(this.grid.customEditors[n]) == 'string'){
55618 return this.editors[this.grid.customEditors[n]];
55620 if(typeof(this.grid.customEditors[n]) != 'undefined'){
55621 return this.grid.customEditors[n];
55623 if(val instanceof Date){
55624 return this.editors['date'];
55625 }else if(typeof val == 'number'){
55626 return this.editors['number'];
55627 }else if(typeof val == 'boolean'){
55628 return this.editors['boolean'];
55630 return this.editors['string'];
55636 * @class Roo.grid.PropertyGrid
55637 * @extends Roo.grid.EditorGrid
55638 * This class represents the interface of a component based property grid control.
55639 * <br><br>Usage:<pre><code>
55640 var grid = new Roo.grid.PropertyGrid("my-container-id", {
55648 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55649 * The container MUST have some type of size defined for the grid to fill. The container will be
55650 * automatically set to position relative if it isn't already.
55651 * @param {Object} config A config object that sets properties on this grid.
55653 Roo.grid.PropertyGrid = function(container, config){
55654 config = config || {};
55655 var store = new Roo.grid.PropertyStore(this);
55656 this.store = store;
55657 var cm = new Roo.grid.PropertyColumnModel(this, store);
55658 store.store.sort('name', 'ASC');
55659 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
55662 enableColLock:false,
55663 enableColumnMove:false,
55665 trackMouseOver: false,
55668 this.getGridEl().addClass('x-props-grid');
55669 this.lastEditRow = null;
55670 this.on('columnresize', this.onColumnResize, this);
55673 * @event beforepropertychange
55674 * Fires before a property changes (return false to stop?)
55675 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
55676 * @param {String} id Record Id
55677 * @param {String} newval New Value
55678 * @param {String} oldval Old Value
55680 "beforepropertychange": true,
55682 * @event propertychange
55683 * Fires after a property changes
55684 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
55685 * @param {String} id Record Id
55686 * @param {String} newval New Value
55687 * @param {String} oldval Old Value
55689 "propertychange": true
55691 this.customEditors = this.customEditors || {};
55693 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
55696 * @cfg {Object} customEditors map of colnames=> custom editors.
55697 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
55698 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
55699 * false disables editing of the field.
55703 * @cfg {Object} propertyNames map of property Names to their displayed value
55706 render : function(){
55707 Roo.grid.PropertyGrid.superclass.render.call(this);
55708 this.autoSize.defer(100, this);
55711 autoSize : function(){
55712 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
55714 this.view.fitColumns();
55718 onColumnResize : function(){
55719 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
55723 * Sets the data for the Grid
55724 * accepts a Key => Value object of all the elements avaiable.
55725 * @param {Object} data to appear in grid.
55727 setSource : function(source){
55728 this.store.setSource(source);
55732 * Gets all the data from the grid.
55733 * @return {Object} data data stored in grid
55735 getSource : function(){
55736 return this.store.getSource();
55740 * Ext JS Library 1.1.1
55741 * Copyright(c) 2006-2007, Ext JS, LLC.
55743 * Originally Released Under LGPL - original licence link has changed is not relivant.
55746 * <script type="text/javascript">
55750 * @class Roo.LoadMask
55751 * A simple utility class for generically masking elements while loading data. If the element being masked has
55752 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
55753 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
55754 * element's UpdateManager load indicator and will be destroyed after the initial load.
55756 * Create a new LoadMask
55757 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
55758 * @param {Object} config The config object
55760 Roo.LoadMask = function(el, config){
55761 this.el = Roo.get(el);
55762 Roo.apply(this, config);
55764 this.store.on('beforeload', this.onBeforeLoad, this);
55765 this.store.on('load', this.onLoad, this);
55766 this.store.on('loadexception', this.onLoadException, this);
55767 this.removeMask = false;
55769 var um = this.el.getUpdateManager();
55770 um.showLoadIndicator = false; // disable the default indicator
55771 um.on('beforeupdate', this.onBeforeLoad, this);
55772 um.on('update', this.onLoad, this);
55773 um.on('failure', this.onLoad, this);
55774 this.removeMask = true;
55778 Roo.LoadMask.prototype = {
55780 * @cfg {Boolean} removeMask
55781 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
55782 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
55785 * @cfg {String} msg
55786 * The text to display in a centered loading message box (defaults to 'Loading...')
55788 msg : 'Loading...',
55790 * @cfg {String} msgCls
55791 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
55793 msgCls : 'x-mask-loading',
55796 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
55802 * Disables the mask to prevent it from being displayed
55804 disable : function(){
55805 this.disabled = true;
55809 * Enables the mask so that it can be displayed
55811 enable : function(){
55812 this.disabled = false;
55815 onLoadException : function()
55817 Roo.log(arguments);
55819 if (typeof(arguments[3]) != 'undefined') {
55820 Roo.MessageBox.alert("Error loading",arguments[3]);
55824 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
55825 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
55834 this.el.unmask(this.removeMask);
55837 onLoad : function()
55839 this.el.unmask(this.removeMask);
55843 onBeforeLoad : function(){
55844 if(!this.disabled){
55845 this.el.mask(this.msg, this.msgCls);
55850 destroy : function(){
55852 this.store.un('beforeload', this.onBeforeLoad, this);
55853 this.store.un('load', this.onLoad, this);
55854 this.store.un('loadexception', this.onLoadException, this);
55856 var um = this.el.getUpdateManager();
55857 um.un('beforeupdate', this.onBeforeLoad, this);
55858 um.un('update', this.onLoad, this);
55859 um.un('failure', this.onLoad, this);
55864 * Ext JS Library 1.1.1
55865 * Copyright(c) 2006-2007, Ext JS, LLC.
55867 * Originally Released Under LGPL - original licence link has changed is not relivant.
55870 * <script type="text/javascript">
55875 * @class Roo.XTemplate
55876 * @extends Roo.Template
55877 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
55879 var t = new Roo.XTemplate(
55880 '<select name="{name}">',
55881 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
55885 // then append, applying the master template values
55888 * Supported features:
55893 {a_variable} - output encoded.
55894 {a_variable.format:("Y-m-d")} - call a method on the variable
55895 {a_variable:raw} - unencoded output
55896 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
55897 {a_variable:this.method_on_template(...)} - call a method on the template object.
55902 <tpl for="a_variable or condition.."></tpl>
55903 <tpl if="a_variable or condition"></tpl>
55904 <tpl exec="some javascript"></tpl>
55905 <tpl name="named_template"></tpl> (experimental)
55907 <tpl for="."></tpl> - just iterate the property..
55908 <tpl for=".."></tpl> - iterates with the parent (probably the template)
55912 Roo.XTemplate = function()
55914 Roo.XTemplate.superclass.constructor.apply(this, arguments);
55921 Roo.extend(Roo.XTemplate, Roo.Template, {
55924 * The various sub templates
55929 * basic tag replacing syntax
55932 * // you can fake an object call by doing this
55936 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
55939 * compile the template
55941 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
55944 compile: function()
55948 s = ['<tpl>', s, '</tpl>'].join('');
55950 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
55951 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
55952 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
55953 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
55954 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
55959 while(true == !!(m = s.match(re))){
55960 var forMatch = m[0].match(nameRe),
55961 ifMatch = m[0].match(ifRe),
55962 execMatch = m[0].match(execRe),
55963 namedMatch = m[0].match(namedRe),
55968 name = forMatch && forMatch[1] ? forMatch[1] : '';
55971 // if - puts fn into test..
55972 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
55974 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
55979 // exec - calls a function... returns empty if true is returned.
55980 exp = execMatch && execMatch[1] ? execMatch[1] : null;
55982 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
55990 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
55991 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
55992 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
55995 var uid = namedMatch ? namedMatch[1] : id;
55999 id: namedMatch ? namedMatch[1] : id,
56006 s = s.replace(m[0], '');
56008 s = s.replace(m[0], '{xtpl'+ id + '}');
56013 for(var i = tpls.length-1; i >= 0; --i){
56014 this.compileTpl(tpls[i]);
56015 this.tpls[tpls[i].id] = tpls[i];
56017 this.master = tpls[tpls.length-1];
56021 * same as applyTemplate, except it's done to one of the subTemplates
56022 * when using named templates, you can do:
56024 * var str = pl.applySubTemplate('your-name', values);
56027 * @param {Number} id of the template
56028 * @param {Object} values to apply to template
56029 * @param {Object} parent (normaly the instance of this object)
56031 applySubTemplate : function(id, values, parent)
56035 var t = this.tpls[id];
56039 if(t.test && !t.test.call(this, values, parent)){
56043 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
56044 Roo.log(e.toString());
56050 if(t.exec && t.exec.call(this, values, parent)){
56054 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
56055 Roo.log(e.toString());
56060 var vs = t.target ? t.target.call(this, values, parent) : values;
56061 parent = t.target ? values : parent;
56062 if(t.target && vs instanceof Array){
56064 for(var i = 0, len = vs.length; i < len; i++){
56065 buf[buf.length] = t.compiled.call(this, vs[i], parent);
56067 return buf.join('');
56069 return t.compiled.call(this, vs, parent);
56071 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
56072 Roo.log(e.toString());
56073 Roo.log(t.compiled);
56078 compileTpl : function(tpl)
56080 var fm = Roo.util.Format;
56081 var useF = this.disableFormats !== true;
56082 var sep = Roo.isGecko ? "+" : ",";
56083 var undef = function(str) {
56084 Roo.log("Property not found :" + str);
56088 var fn = function(m, name, format, args)
56090 //Roo.log(arguments);
56091 args = args ? args.replace(/\\'/g,"'") : args;
56092 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
56093 if (typeof(format) == 'undefined') {
56094 format= 'htmlEncode';
56096 if (format == 'raw' ) {
56100 if(name.substr(0, 4) == 'xtpl'){
56101 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
56104 // build an array of options to determine if value is undefined..
56106 // basically get 'xxxx.yyyy' then do
56107 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
56108 // (function () { Roo.log("Property not found"); return ''; })() :
56113 Roo.each(name.split('.'), function(st) {
56114 lookfor += (lookfor.length ? '.': '') + st;
56115 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
56118 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
56121 if(format && useF){
56123 args = args ? ',' + args : "";
56125 if(format.substr(0, 5) != "this."){
56126 format = "fm." + format + '(';
56128 format = 'this.call("'+ format.substr(5) + '", ';
56132 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
56136 // called with xxyx.yuu:(test,test)
56138 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
56140 // raw.. - :raw modifier..
56141 return "'"+ sep + udef_st + name + ")"+sep+"'";
56145 // branched to use + in gecko and [].join() in others
56147 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
56148 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
56151 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
56152 body.push(tpl.body.replace(/(\r\n|\n)/g,
56153 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
56154 body.push("'].join('');};};");
56155 body = body.join('');
56158 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
56160 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
56166 applyTemplate : function(values){
56167 return this.master.compiled.call(this, values, {});
56168 //var s = this.subs;
56171 apply : function(){
56172 return this.applyTemplate.apply(this, arguments);
56177 Roo.XTemplate.from = function(el){
56178 el = Roo.getDom(el);
56179 return new Roo.XTemplate(el.value || el.innerHTML);